ansible-test pssa update and new rules (#76256)
This commit is contained in:
parent
90de24da7b
commit
9985b8a975
|
@ -0,0 +1,17 @@
|
|||
minor_changes:
|
||||
- ansible-test pslint - Updated ``PowerShellScriptAnalyzer`` to 1.20.0
|
||||
- >-
|
||||
ansible-test pslint - Added the `AvoidLongLines <https://github.com/PowerShell/PSScriptAnalyzer/blob/master/docs/Rules/AvoidLongLines.md>`_
|
||||
rule set to a length of 160.
|
||||
- >-
|
||||
ansible-test pslint - Added the `PlaceOpenBrace <https://github.com/PowerShell/PSScriptAnalyzer/blob/master/docs/Rules/PlaceOpenBrace.md>`_
|
||||
rule set to enforce open braces on the same line and a subsequent newline.
|
||||
- >-
|
||||
ansible-test pslint - Added the `PlaceCloseBrace <https://github.com/PowerShell/PSScriptAnalyzer/blob/master/docs/Rules/PlaceCloseBrace.md>`_
|
||||
rule set to enforce close braces on a newline.
|
||||
- >-
|
||||
ansible-test pslint - Added the `UseConsistentIndentation <https://github.com/PowerShell/PSScriptAnalyzer/blob/master/docs/Rules/UseConsistentIndentation.md>`_
|
||||
rule to enforce indentation is done with 4 spaces.
|
||||
- >-
|
||||
ansible-test pslint - Added the `UseConsistentWhitespace <https://github.com/PowerShell/PSScriptAnalyzer/blob/master/docs/Rules/UseConsistentWhitespace.md>`_
|
||||
rule to enforce whitespace consistency in PowerShell.
|
|
@ -66,28 +66,24 @@ Param (
|
|||
[switch]$EnableCredSSP
|
||||
)
|
||||
|
||||
Function Write-Log
|
||||
{
|
||||
Function Write-ProgressLog {
|
||||
$Message = $args[0]
|
||||
Write-EventLog -LogName Application -Source $EventSource -EntryType Information -EventId 1 -Message $Message
|
||||
}
|
||||
|
||||
Function Write-VerboseLog
|
||||
{
|
||||
Function Write-VerboseLog {
|
||||
$Message = $args[0]
|
||||
Write-Verbose $Message
|
||||
Write-Log $Message
|
||||
Write-ProgressLog $Message
|
||||
}
|
||||
|
||||
Function Write-HostLog
|
||||
{
|
||||
Function Write-HostLog {
|
||||
$Message = $args[0]
|
||||
Write-Output $Message
|
||||
Write-Log $Message
|
||||
Write-ProgressLog $Message
|
||||
}
|
||||
|
||||
Function New-LegacySelfSignedCert
|
||||
{
|
||||
Function New-LegacySelfSignedCert {
|
||||
Param (
|
||||
[string]$SubjectName,
|
||||
[int]$ValidDays = 1095
|
||||
|
@ -125,14 +121,13 @@ Function New-LegacySelfSignedCert
|
|||
$SigOID = New-Object -ComObject X509Enrollment.CObjectId
|
||||
$SigOID.InitializeFromValue(([Security.Cryptography.Oid]$SignatureAlgorithm).Value)
|
||||
|
||||
[string[]] $AlternativeName += $hostnonFQDN
|
||||
[string[]] $AlternativeName += $hostnonFQDN
|
||||
$AlternativeName += $hostFQDN
|
||||
$IAlternativeNames = New-Object -ComObject X509Enrollment.CAlternativeNames
|
||||
|
||||
foreach ($AN in $AlternativeName)
|
||||
{
|
||||
foreach ($AN in $AlternativeName) {
|
||||
$AltName = New-Object -ComObject X509Enrollment.CAlternativeName
|
||||
$AltName.InitializeFromString(0x3,$AN)
|
||||
$AltName.InitializeFromString(0x3, $AN)
|
||||
$IAlternativeNames.Add($AltName)
|
||||
}
|
||||
|
||||
|
@ -162,15 +157,14 @@ Function New-LegacySelfSignedCert
|
|||
return $parsed_cert.Thumbprint
|
||||
}
|
||||
|
||||
Function Enable-GlobalHttpFirewallAccess
|
||||
{
|
||||
Function Enable-GlobalHttpFirewallAccess {
|
||||
Write-Verbose "Forcing global HTTP firewall access"
|
||||
# this is a fairly naive implementation; could be more sophisticated about rule matching/collapsing
|
||||
$fw = New-Object -ComObject HNetCfg.FWPolicy2
|
||||
|
||||
# try to find/enable the default rule first
|
||||
$add_rule = $false
|
||||
$matching_rules = $fw.Rules | Where-Object { $_.Name -eq "Windows Remote Management (HTTP-In)" }
|
||||
$matching_rules = $fw.Rules | Where-Object { $_.Name -eq "Windows Remote Management (HTTP-In)" }
|
||||
$rule = $null
|
||||
If ($matching_rules) {
|
||||
If ($matching_rules -isnot [Array]) {
|
||||
|
@ -217,80 +211,71 @@ Function Enable-GlobalHttpFirewallAccess
|
|||
}
|
||||
|
||||
# Setup error handling.
|
||||
Trap
|
||||
{
|
||||
Trap {
|
||||
$_
|
||||
Exit 1
|
||||
}
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Get the ID and security principal of the current user account
|
||||
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
|
||||
$myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$myWindowsPrincipal = new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
|
||||
|
||||
# Get the security principal for the Administrator role
|
||||
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
|
||||
$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator
|
||||
|
||||
# Check to see if we are currently running "as Administrator"
|
||||
if (-Not $myWindowsPrincipal.IsInRole($adminRole))
|
||||
{
|
||||
if (-Not $myWindowsPrincipal.IsInRole($adminRole)) {
|
||||
Write-Output "ERROR: You need elevated Administrator privileges in order to run this script."
|
||||
Write-Output " Start Windows PowerShell by using the Run as Administrator option."
|
||||
Exit 2
|
||||
}
|
||||
|
||||
$EventSource = $MyInvocation.MyCommand.Name
|
||||
If (-Not $EventSource)
|
||||
{
|
||||
If (-Not $EventSource) {
|
||||
$EventSource = "Powershell CLI"
|
||||
}
|
||||
|
||||
If ([System.Diagnostics.EventLog]::Exists('Application') -eq $False -or [System.Diagnostics.EventLog]::SourceExists($EventSource) -eq $False)
|
||||
{
|
||||
If ([System.Diagnostics.EventLog]::Exists('Application') -eq $False -or [System.Diagnostics.EventLog]::SourceExists($EventSource) -eq $False) {
|
||||
New-EventLog -LogName Application -Source $EventSource
|
||||
}
|
||||
|
||||
# Detect PowerShell version.
|
||||
If ($PSVersionTable.PSVersion.Major -lt 3)
|
||||
{
|
||||
Write-Log "PowerShell version 3 or higher is required."
|
||||
If ($PSVersionTable.PSVersion.Major -lt 3) {
|
||||
Write-ProgressLog "PowerShell version 3 or higher is required."
|
||||
Throw "PowerShell version 3 or higher is required."
|
||||
}
|
||||
|
||||
# Find and start the WinRM service.
|
||||
Write-Verbose "Verifying WinRM service."
|
||||
If (!(Get-Service "WinRM"))
|
||||
{
|
||||
Write-Log "Unable to find the WinRM service."
|
||||
If (!(Get-Service "WinRM")) {
|
||||
Write-ProgressLog "Unable to find the WinRM service."
|
||||
Throw "Unable to find the WinRM service."
|
||||
}
|
||||
ElseIf ((Get-Service "WinRM").Status -ne "Running")
|
||||
{
|
||||
ElseIf ((Get-Service "WinRM").Status -ne "Running") {
|
||||
Write-Verbose "Setting WinRM service to start automatically on boot."
|
||||
Set-Service -Name "WinRM" -StartupType Automatic
|
||||
Write-Log "Set WinRM service to start automatically on boot."
|
||||
Write-ProgressLog "Set WinRM service to start automatically on boot."
|
||||
Write-Verbose "Starting WinRM service."
|
||||
Start-Service -Name "WinRM" -ErrorAction Stop
|
||||
Write-Log "Started WinRM service."
|
||||
Write-ProgressLog "Started WinRM service."
|
||||
|
||||
}
|
||||
|
||||
# WinRM should be running; check that we have a PS session config.
|
||||
If (!(Get-PSSessionConfiguration -Verbose:$false) -or (!(Get-ChildItem WSMan:\localhost\Listener)))
|
||||
{
|
||||
If ($SkipNetworkProfileCheck) {
|
||||
Write-Verbose "Enabling PS Remoting without checking Network profile."
|
||||
Enable-PSRemoting -SkipNetworkProfileCheck -Force -ErrorAction Stop
|
||||
Write-Log "Enabled PS Remoting without checking Network profile."
|
||||
}
|
||||
Else {
|
||||
Write-Verbose "Enabling PS Remoting."
|
||||
Enable-PSRemoting -Force -ErrorAction Stop
|
||||
Write-Log "Enabled PS Remoting."
|
||||
}
|
||||
If (!(Get-PSSessionConfiguration -Verbose:$false) -or (!(Get-ChildItem WSMan:\localhost\Listener))) {
|
||||
If ($SkipNetworkProfileCheck) {
|
||||
Write-Verbose "Enabling PS Remoting without checking Network profile."
|
||||
Enable-PSRemoting -SkipNetworkProfileCheck -Force -ErrorAction Stop
|
||||
Write-ProgressLog "Enabled PS Remoting without checking Network profile."
|
||||
}
|
||||
Else {
|
||||
Write-Verbose "Enabling PS Remoting."
|
||||
Enable-PSRemoting -Force -ErrorAction Stop
|
||||
Write-ProgressLog "Enabled PS Remoting."
|
||||
}
|
||||
}
|
||||
Else
|
||||
{
|
||||
Else {
|
||||
Write-Verbose "PS Remoting is already enabled."
|
||||
}
|
||||
|
||||
|
@ -310,8 +295,7 @@ if ($token_value -ne 1) {
|
|||
|
||||
# Make sure there is a SSL listener.
|
||||
$listeners = Get-ChildItem WSMan:\localhost\Listener
|
||||
If (!($listeners | Where-Object {$_.Keys -like "TRANSPORT=HTTPS"}))
|
||||
{
|
||||
If (!($listeners | Where-Object { $_.Keys -like "TRANSPORT=HTTPS" })) {
|
||||
# We cannot use New-SelfSignedCertificate on 2012R2 and earlier
|
||||
$thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName -ValidDays $CertValidityDays
|
||||
Write-HostLog "Self-signed SSL certificate generated; thumbprint: $thumbprint"
|
||||
|
@ -329,15 +313,13 @@ If (!($listeners | Where-Object {$_.Keys -like "TRANSPORT=HTTPS"}))
|
|||
|
||||
Write-Verbose "Enabling SSL listener."
|
||||
New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset
|
||||
Write-Log "Enabled SSL listener."
|
||||
Write-ProgressLog "Enabled SSL listener."
|
||||
}
|
||||
Else
|
||||
{
|
||||
Else {
|
||||
Write-Verbose "SSL listener is already active."
|
||||
|
||||
# Force a new SSL cert on Listener if the $ForceNewSSLCert
|
||||
If ($ForceNewSSLCert)
|
||||
{
|
||||
If ($ForceNewSSLCert) {
|
||||
|
||||
# We cannot use New-SelfSignedCertificate on 2012R2 and earlier
|
||||
$thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName -ValidDays $CertValidityDays
|
||||
|
@ -361,45 +343,37 @@ Else
|
|||
}
|
||||
|
||||
# Check for basic authentication.
|
||||
$basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object {$_.Name -eq "Basic"}
|
||||
$basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object { $_.Name -eq "Basic" }
|
||||
|
||||
If ($DisableBasicAuth)
|
||||
{
|
||||
If (($basicAuthSetting.Value) -eq $true)
|
||||
{
|
||||
If ($DisableBasicAuth) {
|
||||
If (($basicAuthSetting.Value) -eq $true) {
|
||||
Write-Verbose "Disabling basic auth support."
|
||||
Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $false
|
||||
Write-Log "Disabled basic auth support."
|
||||
Write-ProgressLog "Disabled basic auth support."
|
||||
}
|
||||
Else
|
||||
{
|
||||
Else {
|
||||
Write-Verbose "Basic auth is already disabled."
|
||||
}
|
||||
}
|
||||
Else
|
||||
{
|
||||
If (($basicAuthSetting.Value) -eq $false)
|
||||
{
|
||||
Else {
|
||||
If (($basicAuthSetting.Value) -eq $false) {
|
||||
Write-Verbose "Enabling basic auth support."
|
||||
Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $true
|
||||
Write-Log "Enabled basic auth support."
|
||||
Write-ProgressLog "Enabled basic auth support."
|
||||
}
|
||||
Else
|
||||
{
|
||||
Else {
|
||||
Write-Verbose "Basic auth is already enabled."
|
||||
}
|
||||
}
|
||||
|
||||
# If EnableCredSSP if set to true
|
||||
If ($EnableCredSSP)
|
||||
{
|
||||
If ($EnableCredSSP) {
|
||||
# Check for CredSSP authentication
|
||||
$credsspAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object {$_.Name -eq "CredSSP"}
|
||||
If (($credsspAuthSetting.Value) -eq $false)
|
||||
{
|
||||
$credsspAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object { $_.Name -eq "CredSSP" }
|
||||
If (($credsspAuthSetting.Value) -eq $false) {
|
||||
Write-Verbose "Enabling CredSSP auth support."
|
||||
Enable-WSManCredSSP -role server -Force
|
||||
Write-Log "Enabled CredSSP auth support."
|
||||
Write-ProgressLog "Enabled CredSSP auth support."
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -410,44 +384,37 @@ If ($GlobalHttpFirewallAccess) {
|
|||
# Configure firewall to allow WinRM HTTPS connections.
|
||||
$fwtest1 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS"
|
||||
$fwtest2 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS" profile=any
|
||||
If ($fwtest1.count -lt 5)
|
||||
{
|
||||
If ($fwtest1.count -lt 5) {
|
||||
Write-Verbose "Adding firewall rule to allow WinRM HTTPS."
|
||||
netsh advfirewall firewall add rule profile=any name="Allow WinRM HTTPS" dir=in localport=5986 protocol=TCP action=allow
|
||||
Write-Log "Added firewall rule to allow WinRM HTTPS."
|
||||
Write-ProgressLog "Added firewall rule to allow WinRM HTTPS."
|
||||
}
|
||||
ElseIf (($fwtest1.count -ge 5) -and ($fwtest2.count -lt 5))
|
||||
{
|
||||
ElseIf (($fwtest1.count -ge 5) -and ($fwtest2.count -lt 5)) {
|
||||
Write-Verbose "Updating firewall rule to allow WinRM HTTPS for any profile."
|
||||
netsh advfirewall firewall set rule name="Allow WinRM HTTPS" new profile=any
|
||||
Write-Log "Updated firewall rule to allow WinRM HTTPS for any profile."
|
||||
Write-ProgressLog "Updated firewall rule to allow WinRM HTTPS for any profile."
|
||||
}
|
||||
Else
|
||||
{
|
||||
Else {
|
||||
Write-Verbose "Firewall rule already exists to allow WinRM HTTPS."
|
||||
}
|
||||
|
||||
# Test a remoting connection to localhost, which should work.
|
||||
$httpResult = Invoke-Command -ComputerName "localhost" -ScriptBlock {$env:COMPUTERNAME} -ErrorVariable httpError -ErrorAction SilentlyContinue
|
||||
$httpResult = Invoke-Command -ComputerName "localhost" -ScriptBlock { $using:env:COMPUTERNAME } -ErrorVariable httpError -ErrorAction SilentlyContinue
|
||||
$httpsOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
|
||||
|
||||
$httpsResult = New-PSSession -UseSSL -ComputerName "localhost" -SessionOption $httpsOptions -ErrorVariable httpsError -ErrorAction SilentlyContinue
|
||||
|
||||
If ($httpResult -and $httpsResult)
|
||||
{
|
||||
If ($httpResult -and $httpsResult) {
|
||||
Write-Verbose "HTTP: Enabled | HTTPS: Enabled"
|
||||
}
|
||||
ElseIf ($httpsResult -and !$httpResult)
|
||||
{
|
||||
ElseIf ($httpsResult -and !$httpResult) {
|
||||
Write-Verbose "HTTP: Disabled | HTTPS: Enabled"
|
||||
}
|
||||
ElseIf ($httpResult -and !$httpsResult)
|
||||
{
|
||||
ElseIf ($httpResult -and !$httpsResult) {
|
||||
Write-Verbose "HTTP: Enabled | HTTPS: Disabled"
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Log "Unable to establish an HTTP or HTTPS remoting session."
|
||||
Else {
|
||||
Write-ProgressLog "Unable to establish an HTTP or HTTPS remoting session."
|
||||
Throw "Unable to establish an HTTP or HTTPS remoting session."
|
||||
}
|
||||
Write-VerboseLog "PS Remoting has been successfully configured for Ansible."
|
||||
|
|
|
@ -18,24 +18,21 @@
|
|||
# 6.3 is 2012 R2
|
||||
|
||||
|
||||
if ($PSVersionTable.psversion.Major -ge 3)
|
||||
{
|
||||
if ($PSVersionTable.psversion.Major -ge 3) {
|
||||
Write-Output "Powershell 3 Installed already; You don't need this"
|
||||
Exit
|
||||
}
|
||||
|
||||
$powershellpath = "C:\powershell"
|
||||
|
||||
function download-file
|
||||
{
|
||||
function download-file {
|
||||
param ([string]$path, [string]$local)
|
||||
$client = new-object system.net.WebClient
|
||||
$client.Headers.Add("user-agent", "PowerShell")
|
||||
$client.downloadfile($path, $local)
|
||||
}
|
||||
|
||||
if (!(test-path $powershellpath))
|
||||
{
|
||||
if (!(test-path $powershellpath)) {
|
||||
New-Item -ItemType directory -Path $powershellpath
|
||||
}
|
||||
|
||||
|
@ -53,8 +50,7 @@ if (!(test-path $powershellpath))
|
|||
#You may need to reboot after the .NET install if so just run the script again.
|
||||
|
||||
# If the Operating System is above 6.2, then you already have PowerShell Version > 3
|
||||
if ([Environment]::OSVersion.Version.Major -gt 6)
|
||||
{
|
||||
if ([Environment]::OSVersion.Version.Major -gt 6) {
|
||||
Write-Output "OS is new; upgrade not needed."
|
||||
Exit
|
||||
}
|
||||
|
@ -64,25 +60,20 @@ $osminor = [environment]::OSVersion.Version.Minor
|
|||
|
||||
$architecture = $ENV:PROCESSOR_ARCHITECTURE
|
||||
|
||||
if ($architecture -eq "AMD64")
|
||||
{
|
||||
if ($architecture -eq "AMD64") {
|
||||
$architecture = "x64"
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
$architecture = "x86"
|
||||
}
|
||||
|
||||
if ($osminor -eq 1)
|
||||
{
|
||||
if ($osminor -eq 1) {
|
||||
$DownloadUrl = "http://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.1-KB2506143-" + $architecture + ".msu"
|
||||
}
|
||||
elseif ($osminor -eq 0)
|
||||
{
|
||||
elseif ($osminor -eq 0) {
|
||||
$DownloadUrl = "http://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.0-KB2506146-" + $architecture + ".msu"
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
# Nothing to do; In theory this point will never be reached.
|
||||
Exit
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Payload
|
||||
[Parameter(Mandatory = $true)][System.Collections.IDictionary]$Payload
|
||||
)
|
||||
|
||||
# help with debugging errors as we don't have visibility of this running process
|
||||
|
@ -49,7 +49,12 @@ $ps.Runspace = $rs
|
|||
Write-AnsibleLog "INFO - adding global functions to PowerShell pipeline script" "async_watchdog"
|
||||
$ps.AddScript($script:common_functions).AddStatement() > $null
|
||||
$ps.AddScript($script:wrapper_functions).AddStatement() > $null
|
||||
$ps.AddCommand("Set-Variable").AddParameters(@{Name="common_functions"; Value=$script:common_functions; Scope="script"}).AddStatement() > $null
|
||||
$function_params = @{
|
||||
Name = "common_functions"
|
||||
Value = $script:common_functions
|
||||
Scope = "script"
|
||||
}
|
||||
$ps.AddCommand("Set-Variable").AddParameters($function_params).AddStatement() > $null
|
||||
|
||||
Write-AnsibleLog "INFO - adding $($actions[0]) to PowerShell pipeline script" "async_watchdog"
|
||||
$ps.AddScript($entrypoint).AddArgument($payload) > $null
|
||||
|
@ -79,7 +84,8 @@ if ($job_async_result.IsCompleted) {
|
|||
$module_result = ConvertFrom-AnsibleJson -InputObject $job_output
|
||||
# TODO: check for conflicting keys
|
||||
$result = $result + $module_result
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
$result.failed = $true
|
||||
$result.msg = "failed to parse module output: $($_.Exception.Message)"
|
||||
# return output back to Ansible to help with debugging errors
|
||||
|
@ -91,7 +97,8 @@ if ($job_async_result.IsCompleted) {
|
|||
Set-Content -Path $resultfile_path -Value $result_json
|
||||
|
||||
Write-AnsibleLog "INFO - wrote output to $resultfile_path" "async_watchdog"
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Write-AnsibleLog "ERROR - reached timeout on async job, stopping job" "async_watchdog"
|
||||
$ps.BeginStop($null, $null) > $null # best effort stop
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Payload
|
||||
[Parameter(Mandatory = $true)][System.Collections.IDictionary]$Payload
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
@ -65,7 +65,7 @@ $bootstrap_wrapper = {
|
|||
|
||||
$input_bytes = New-Object -TypeName byte[] -ArgumentList $bytes_length
|
||||
$pipe = New-Object -TypeName System.IO.Pipes.NamedPipeClientStream -ArgumentList @(
|
||||
".", # localhost
|
||||
".", # localhost
|
||||
$pipe_name,
|
||||
[System.IO.Pipes.PipeDirection]::In,
|
||||
[System.IO.Pipes.PipeOptions]::None,
|
||||
|
@ -74,7 +74,8 @@ $bootstrap_wrapper = {
|
|||
try {
|
||||
$pipe.Connect()
|
||||
$pipe.Read($input_bytes, 0, $bytes_length) > $null
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
$pipe.Close()
|
||||
}
|
||||
$exec = [System.Text.Encoding]::UTF8.GetString($input_bytes)
|
||||
|
@ -114,12 +115,12 @@ $pipe = New-Object -TypeName System.IO.Pipes.NamedPipeServerStream -ArgumentList
|
|||
|
||||
try {
|
||||
Write-AnsibleLog "INFO - creating async process '$exec_args'" "async_wrapper"
|
||||
$process = Invoke-CimMethod -ClassName Win32_Process -Name Create -Arguments @{CommandLine=$exec_args}
|
||||
$process = Invoke-CimMethod -ClassName Win32_Process -Name Create -Arguments @{CommandLine = $exec_args }
|
||||
$rc = $process.ReturnValue
|
||||
|
||||
Write-AnsibleLog "INFO - return value from async process exec: $rc" "async_wrapper"
|
||||
if ($rc -ne 0) {
|
||||
$error_msg = switch($rc) {
|
||||
$error_msg = switch ($rc) {
|
||||
2 { "Access denied" }
|
||||
3 { "Insufficient privilege" }
|
||||
8 { "Unknown failure" }
|
||||
|
@ -163,7 +164,8 @@ try {
|
|||
$pipe.Write($payload_bytes, 0, $payload_bytes.Count)
|
||||
$pipe.Flush()
|
||||
$pipe.WaitForPipeDrain()
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
$pipe.Close()
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Payload
|
||||
[Parameter(Mandatory = $true)][System.Collections.IDictionary]$Payload
|
||||
)
|
||||
|
||||
#Requires -Module Ansible.ModuleUtils.AddType
|
||||
|
@ -17,7 +17,8 @@ Function Get-EnumValue($enum, $flag_type, $value) {
|
|||
$raw_enum_value = $value.Replace('_', '')
|
||||
try {
|
||||
$enum_value = [Enum]::Parse($enum, $raw_enum_value, $true)
|
||||
} catch [System.ArgumentException] {
|
||||
}
|
||||
catch [System.ArgumentException] {
|
||||
$valid_options = [Enum]::GetNames($enum) | ForEach-Object -Process {
|
||||
(($_ -creplace "(.)([A-Z][a-z]+)", '$1_$2') -creplace "([a-z0-9])([A-Z])", '$1_$2').ToString().ToLower()
|
||||
}
|
||||
|
@ -26,15 +27,17 @@ Function Get-EnumValue($enum, $flag_type, $value) {
|
|||
return $enum_value
|
||||
}
|
||||
|
||||
Function Get-BecomeFlags($flags) {
|
||||
Function Get-BecomeFlag($flags) {
|
||||
$logon_type = [Ansible.AccessToken.LogonType]::Interactive
|
||||
$logon_flags = [Ansible.Become.LogonFlags]::WithProfile
|
||||
|
||||
if ($null -eq $flags -or $flags -eq "") {
|
||||
$flag_split = @()
|
||||
} elseif ($flags -is [string]) {
|
||||
}
|
||||
elseif ($flags -is [string]) {
|
||||
$flag_split = $flags.Split(" ")
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
throw "become_flags must be a string, was $($flags.GetType())"
|
||||
}
|
||||
|
||||
|
@ -52,7 +55,8 @@ Function Get-BecomeFlags($flags) {
|
|||
value = $flag_value
|
||||
}
|
||||
$logon_type = Get-EnumValue @enum_details
|
||||
} elseif ($flag_key -eq "logon_flags") {
|
||||
}
|
||||
elseif ($flag_key -eq "logon_flags") {
|
||||
$logon_flag_values = $flag_value.Split(",")
|
||||
$logon_flags = 0 -as [Ansible.Become.LogonFlags]
|
||||
foreach ($logon_flag_value in $logon_flag_values) {
|
||||
|
@ -67,7 +71,8 @@ Function Get-BecomeFlags($flags) {
|
|||
$logon_flag = Get-EnumValue @enum_details
|
||||
$logon_flags = $logon_flags -bor $logon_flag
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
throw "become_flags key '$flag_key' is not a valid runas flag, must be 'logon_type' or 'logon_flags'"
|
||||
}
|
||||
}
|
||||
|
@ -96,8 +101,9 @@ if ($null -eq $password) {
|
|||
}
|
||||
|
||||
try {
|
||||
$logon_type, $logon_flags = Get-BecomeFlags -flags $Payload.become_flags
|
||||
} catch {
|
||||
$logon_type, $logon_flags = Get-BecomeFlag -flags $Payload.become_flags
|
||||
}
|
||||
catch {
|
||||
Write-AnsibleError -Message "internal error: failed to parse become_flags '$($Payload.become_flags)'" -ErrorRecord $_
|
||||
$host.SetShouldExit(1)
|
||||
return
|
||||
|
@ -134,12 +140,13 @@ $exec_wrapper += "`0`0`0`0" + $payload_json
|
|||
try {
|
||||
Write-AnsibleLog "INFO - starting become process '$lp_command_line'" "become_wrapper"
|
||||
$result = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($username, $password, $logon_flags, $logon_type,
|
||||
$null, $lp_command_line, $lp_current_directory, $null, $exec_wrapper)
|
||||
$null, $lp_command_line, $lp_current_directory, $null, $exec_wrapper)
|
||||
Write-AnsibleLog "INFO - become process complete with rc: $($result.ExitCode)" "become_wrapper"
|
||||
$stdout = $result.StandardOut
|
||||
try {
|
||||
$stdout = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($stdout))
|
||||
} catch [FormatException] {
|
||||
}
|
||||
catch [FormatException] {
|
||||
# output wasn't Base64, ignore as it may contain an error message we want to pass to Ansible
|
||||
Write-AnsibleLog "WARN - become process stdout was not base64 encoded as expected: $stdout"
|
||||
}
|
||||
|
@ -147,7 +154,8 @@ try {
|
|||
$host.UI.WriteLine($stdout)
|
||||
$host.UI.WriteErrorLine($result.StandardError.Trim())
|
||||
$host.SetShouldExit($result.ExitCode)
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
Write-AnsibleError -Message "internal error: failed to become user '$username'" -ErrorRecord $_
|
||||
$host.SetShouldExit(1)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Payload
|
||||
[Parameter(Mandatory = $true)][System.Collections.IDictionary]$Payload
|
||||
)
|
||||
|
||||
#AnsibleRequires -Wrapper module_wrapper
|
||||
|
@ -159,7 +159,8 @@ try {
|
|||
|
||||
try {
|
||||
&$entrypoint @params
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
# Processing here is kept to an absolute minimum to make sure each task runtime is kept as small as
|
||||
# possible. Once all the tests have been run ansible-test will collect this info and process it locally in
|
||||
# one go.
|
||||
|
@ -180,14 +181,16 @@ try {
|
|||
$utf8_no_bom = New-Object -TypeName System.Text.UTF8Encoding -ArgumentList $false
|
||||
[System.IO.File]::WriteAllbytes($coverage_output_path, $utf8_no_bom.GetBytes($code_cov_json))
|
||||
}
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if ($breakpoint_info) {
|
||||
foreach ($b in $breakpoint_info.Breakpoints) {
|
||||
Remove-PSBreakpoint -Breakpoint $b
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
Write-AnsibleLog "INFO - Remove temp coverage folder '$temp_path'" "coverage_wrapper"
|
||||
Remove-Item -LiteralPath $temp_path -Force -Recurse
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ begin {
|
|||
[String] The JSON string to deserialize.
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=0)][String]$InputObject
|
||||
[Parameter(Mandatory = $true, Position = 0)][String]$InputObject
|
||||
)
|
||||
|
||||
# we can use -AsHashtable to get PowerShell to convert the JSON to
|
||||
|
@ -30,8 +30,9 @@ begin {
|
|||
# 6.0, fall back to a manual conversion for older versions
|
||||
$cmdlet = Get-Command -Name ConvertFrom-Json -CommandType Cmdlet
|
||||
if ("AsHashtable" -in $cmdlet.Parameters.Keys) {
|
||||
return ,(ConvertFrom-Json -InputObject $InputObject -AsHashtable)
|
||||
} else {
|
||||
return , (ConvertFrom-Json -InputObject $InputObject -AsHashtable)
|
||||
}
|
||||
else {
|
||||
# get the PSCustomObject and then manually convert from there
|
||||
$raw_obj = ConvertFrom-Json -InputObject $InputObject
|
||||
|
||||
|
@ -47,18 +48,20 @@ begin {
|
|||
foreach ($prop in $InputObject.PSObject.Properties.GetEnumerator()) {
|
||||
$new_value.($prop.Name) = (ConvertTo-Hashtable -InputObject $prop.Value)
|
||||
}
|
||||
return ,$new_value
|
||||
} elseif ($InputObject -is [Array]) {
|
||||
return , $new_value
|
||||
}
|
||||
elseif ($InputObject -is [Array]) {
|
||||
$new_value = [System.Collections.ArrayList]@()
|
||||
foreach ($val in $InputObject) {
|
||||
$new_value.Add((ConvertTo-Hashtable -InputObject $val)) > $null
|
||||
}
|
||||
return ,$new_value.ToArray()
|
||||
} else {
|
||||
return ,$InputObject
|
||||
return , $new_value.ToArray()
|
||||
}
|
||||
else {
|
||||
return , $InputObject
|
||||
}
|
||||
}
|
||||
return ,(ConvertTo-Hashtable -InputObject $raw_obj)
|
||||
return , (ConvertTo-Hashtable -InputObject $raw_obj)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,7 +110,7 @@ $($ErrorRecord.InvocationInfo.PositionMessage)
|
|||
ErrorRecord is passed through.
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][String]$Message,
|
||||
[Parameter(Mandatory = $true)][String]$Message,
|
||||
[System.Management.Automation.ErrorRecord]$ErrorRecord = $null
|
||||
)
|
||||
$result = @{
|
||||
|
@ -130,8 +133,8 @@ $($ErrorRecord.InvocationInfo.PositionMessage)
|
|||
an env value on the Windows host that this is run on to enable.
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=0)][String]$Message,
|
||||
[Parameter(Position=1)][String]$Wrapper
|
||||
[Parameter(Mandatory = $true, Position = 0)][String]$Message,
|
||||
[Parameter(Position = 1)][String]$Wrapper
|
||||
)
|
||||
|
||||
$log_path = $env:ANSIBLE_EXEC_DEBUG
|
||||
|
@ -150,7 +153,8 @@ $($ErrorRecord.InvocationInfo.PositionMessage)
|
|||
[System.IO.FileAccess]::Write, [System.IO.FileShare]::ReadWrite)
|
||||
try {
|
||||
$fs.Write($msg_bytes, 0, $msg_bytes.Length)
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
$fs.Close()
|
||||
}
|
||||
}
|
||||
|
@ -186,7 +190,8 @@ $($ErrorRecord.InvocationInfo.PositionMessage)
|
|||
|
||||
Write-AnsibleLog "INFO - checking if actual os version '$actual_os_version' is less than the min os version '$min_os_version'" "exec_wrapper"
|
||||
if ($actual_os_version -lt $min_os_version) {
|
||||
Write-AnsibleError -Message "internal error: This module cannot run on this OS as it requires a minimum version of $min_os_version, actual was $actual_os_version"
|
||||
$msg = "internal error: This module cannot run on this OS as it requires a minimum version of $min_os_version, actual was $actual_os_version"
|
||||
Write-AnsibleError -Message $msg
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
@ -196,7 +201,8 @@ $($ErrorRecord.InvocationInfo.PositionMessage)
|
|||
|
||||
Write-AnsibleLog "INFO - checking if actual PS version '$actual_ps_version' is less than the min PS version '$min_ps_version'" "exec_wrapper"
|
||||
if ($actual_ps_version -lt $min_ps_version) {
|
||||
Write-AnsibleError -Message "internal error: This module cannot run as it requires a minimum PowerShell version of $min_ps_version, actual was $actual_ps_version"
|
||||
$msg = "internal error: This module cannot run as it requires a minimum PowerShell version of $min_ps_version, actual was $actual_ps_version"
|
||||
Write-AnsibleError -Message $msg
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
@ -218,10 +224,12 @@ $($ErrorRecord.InvocationInfo.PositionMessage)
|
|||
if ($encoded_output -and $null -ne $output) {
|
||||
$b64_output = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($output))
|
||||
Write-Output -InputObject $b64_output
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$output
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
Write-AnsibleError -Message "internal error: failed to run exec_wrapper action $action" -ErrorRecord $_
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Payload
|
||||
[Parameter(Mandatory = $true)][System.Collections.IDictionary]$Payload
|
||||
)
|
||||
|
||||
#AnsibleRequires -Wrapper module_wrapper
|
||||
|
@ -38,7 +38,8 @@ if ($Payload.ContainsKey("coverage") -and $null -ne $host.Runspace -and $null -n
|
|||
$params = @{
|
||||
Payload = $Payload
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
# get the common module_wrapper code and invoke that to run the module
|
||||
$module = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Payload.module_entry))
|
||||
$variables = [System.Collections.ArrayList]@(@{ Name = "complex_args"; Value = $Payload.module_args; Scope = "Global" })
|
||||
|
@ -58,7 +59,8 @@ $entrypoint = [ScriptBlock]::Create($entrypoint)
|
|||
|
||||
try {
|
||||
&$entrypoint @params
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
# failed to invoke the PowerShell module, capture the exception and
|
||||
# output a pretty error for Ansible to parse
|
||||
$result = @{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Payload
|
||||
[Parameter(Mandatory = $true)][System.Collections.IDictionary]$Payload
|
||||
)
|
||||
|
||||
#AnsibleRequires -Wrapper module_wrapper
|
||||
|
|
|
@ -83,7 +83,7 @@ if ($Modules) {
|
|||
Write-AnsibleLog "INFO - create module util '$($module.Key)' for $ModuleName" "module_wrapper"
|
||||
$module_name = $module.Key
|
||||
$module_code = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($module.Value))
|
||||
$ps.AddCommand("New-Module").AddParameters(@{Name=$module_name; ScriptBlock=[ScriptBlock]::Create($module_code)}) > $null
|
||||
$ps.AddCommand("New-Module").AddParameters(@{Name = $module_name; ScriptBlock = [ScriptBlock]::Create($module_code) }) > $null
|
||||
$ps.AddCommand("Import-Module").AddParameter("WarningAction", "SilentlyContinue") > $null
|
||||
$ps.AddCommand("Out-Null").AddStatement() > $null
|
||||
}
|
||||
|
@ -108,9 +108,10 @@ if ($Breakpoints.Count -gt 0) {
|
|||
'AddLineBreakpoint', [System.Reflection.BindingFlags]'Instance, NonPublic'
|
||||
)
|
||||
foreach ($b in $Breakpoints) {
|
||||
$set_method.Invoke($ps.Runspace.Debugger, [Object[]]@(,$b)) > $null
|
||||
$set_method.Invoke($ps.Runspace.Debugger, [Object[]]@(, $b)) > $null
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$ps.Runspace.Debugger.SetBreakpoints($Breakpoints)
|
||||
}
|
||||
}
|
||||
|
@ -126,7 +127,8 @@ $new_out = New-Object -TypeName System.IO.StringWriter -ArgumentList $sb
|
|||
try {
|
||||
[System.Console]::SetOut($new_out)
|
||||
$module_output = $ps.Invoke()
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
# uncaught exception while executing module, present a prettier error for
|
||||
# Ansible to parse
|
||||
$error_params = @{
|
||||
|
@ -147,7 +149,8 @@ try {
|
|||
Write-AnsibleError @error_params
|
||||
$host.SetShouldExit(1)
|
||||
return
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
[System.Console]::SetOut($orig_out)
|
||||
$new_out.Dispose()
|
||||
}
|
||||
|
@ -166,9 +169,11 @@ if ($ps.InvocationStateInfo.State -eq "Failed" -and $ModuleName -ne "script") {
|
|||
# options.
|
||||
if ($null -eq $reason) {
|
||||
$error_params.Message += ": Unknown error"
|
||||
} elseif ($reason.PSObject.Properties.Name -contains "ErrorRecord") {
|
||||
}
|
||||
elseif ($reason.PSObject.Properties.Name -contains "ErrorRecord") {
|
||||
$error_params.ErrorRecord = $reason.ErrorRecord
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$error_params.Message += ": $($reason.ToString())"
|
||||
}
|
||||
|
||||
|
|
|
@ -67,12 +67,12 @@ Function Add-CSharpType {
|
|||
//TypeAccelerator -Name <AcceleratorName> -TypeName <Name of compiled type>
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][AllowEmptyCollection()][String[]]$References,
|
||||
[Parameter(Mandatory = $true)][AllowEmptyCollection()][String[]]$References,
|
||||
[Switch]$IgnoreWarnings,
|
||||
[Switch]$PassThru,
|
||||
[Parameter(Mandatory=$true, ParameterSetName="Module")][Object]$AnsibleModule,
|
||||
[Parameter(ParameterSetName="Manual")][String]$TempPath = $env:TMP,
|
||||
[Parameter(ParameterSetName="Manual")][Switch]$IncludeDebugInfo,
|
||||
[Parameter(Mandatory = $true, ParameterSetName = "Module")][Object]$AnsibleModule,
|
||||
[Parameter(ParameterSetName = "Manual")][String]$TempPath = $env:TMP,
|
||||
[Parameter(ParameterSetName = "Manual")][Switch]$IncludeDebugInfo,
|
||||
[String[]]$CompileSymbols = @()
|
||||
)
|
||||
if ($null -eq $References -or $References.Length -eq 0) {
|
||||
|
@ -86,7 +86,8 @@ Function Add-CSharpType {
|
|||
|
||||
if ([System.IntPtr]::Size -eq 4) {
|
||||
$defined_symbols.Add('X86') > $null
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$defined_symbols.Add('AMD64') > $null
|
||||
}
|
||||
|
||||
|
@ -100,10 +101,12 @@ Function Add-CSharpType {
|
|||
if ($null -ne $is_windows) {
|
||||
if ($is_windows.Value) {
|
||||
$defined_symbols.Add("WINDOWS") > $null
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$defined_symbols.Add("UNIX") > $null
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$defined_symbols.Add("WINDOWS") > $null
|
||||
}
|
||||
|
||||
|
@ -155,7 +158,8 @@ Function Add-CSharpType {
|
|||
$assembly_path = $match.Groups["Name"].Value
|
||||
if ($parameter_type -eq "Type") {
|
||||
$assembly_path = ([Type]$assembly_path).Assembly.Location
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (-not ([System.IO.Path]::IsPathRooted($assembly_path))) {
|
||||
$assembly_path = Join-Path -Path $lib_assembly_location -ChildPath $assembly_path
|
||||
}
|
||||
|
@ -174,15 +178,15 @@ Function Add-CSharpType {
|
|||
|
||||
$type_matches = $type_pattern.Matches($reference)
|
||||
foreach ($match in $type_matches) {
|
||||
$type_accelerators.Add(@{Name=$match.Groups["Name"].Value; TypeName=$match.Groups["TypeName"].Value})
|
||||
$type_accelerators.Add(@{Name = $match.Groups["Name"].Value; TypeName = $match.Groups["TypeName"].Value })
|
||||
}
|
||||
}
|
||||
|
||||
# Release seems to contain the correct line numbers compared to
|
||||
# debug,may need to keep a closer eye on this in the future
|
||||
$compiler_options = (New-Object -TypeName Microsoft.CodeAnalysis.CSharp.CSharpCompilationOptions -ArgumentList @(
|
||||
[Microsoft.CodeAnalysis.OutputKind]::DynamicallyLinkedLibrary
|
||||
)).WithOptimizationLevel([Microsoft.CodeAnalysis.OptimizationLevel]::Release)
|
||||
[Microsoft.CodeAnalysis.OutputKind]::DynamicallyLinkedLibrary
|
||||
)).WithOptimizationLevel([Microsoft.CodeAnalysis.OptimizationLevel]::Release)
|
||||
|
||||
# set warnings to error out if IgnoreWarnings is not set
|
||||
if (-not $IgnoreWarnings.IsPresent) {
|
||||
|
@ -246,18 +250,21 @@ Function Add-CSharpType {
|
|||
$code_ms.Seek(0, [System.IO.SeekOrigin]::Begin) > $null
|
||||
$pdb_ms.Seek(0, [System.IO.SeekOrigin]::Begin) > $null
|
||||
$compiled_assembly = [System.Runtime.Loader.AssemblyLoadContext]::Default.LoadFromStream($code_ms, $pdb_ms)
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
$code_ms.Close()
|
||||
$pdb_ms.Close()
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
# compile the code using CodeDom on PSDesktop
|
||||
|
||||
# configure compile options based on input
|
||||
if ($PSCmdlet.ParameterSetName -eq "Module") {
|
||||
$temp_path = $AnsibleModule.Tmpdir
|
||||
$include_debug = $AnsibleModule.Verbosity -ge 3
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$temp_path = $TempPath
|
||||
$include_debug = $IncludeDebugInfo.IsPresent
|
||||
}
|
||||
|
@ -321,7 +328,7 @@ Function Add-CSharpType {
|
|||
|
||||
$type_matches = $type_pattern.Matches($reference)
|
||||
foreach ($match in $type_matches) {
|
||||
$type_accelerators.Add(@{Name=$match.Groups["Name"].Value; TypeName=$match.Groups["TypeName"].Value})
|
||||
$type_accelerators.Add(@{Name = $match.Groups["Name"].Value; TypeName = $match.Groups["TypeName"].Value })
|
||||
}
|
||||
}
|
||||
if ($ignore_warnings.Count -gt 0) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
# https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments
|
||||
# https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
|
||||
|
||||
Function Escape-Argument($argument, $force_quote=$false) {
|
||||
Function Escape-Argument($argument, $force_quote = $false) {
|
||||
# this converts a single argument to an escaped version, use Join-Arguments
|
||||
# instead of this function as this only escapes a single string.
|
||||
|
||||
|
@ -14,7 +14,8 @@ Function Escape-Argument($argument, $force_quote=$false) {
|
|||
# argument does not need escaping (and we don't want to force it),
|
||||
# return as is
|
||||
return $argument
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
# we need to quote the arg so start with "
|
||||
$new_argument = '"'
|
||||
|
||||
|
@ -28,16 +29,18 @@ Function Escape-Argument($argument, $force_quote=$false) {
|
|||
}
|
||||
|
||||
$current_char = $argument[$i]
|
||||
if ($i -eq ($argument.Length -1) -and $current_char -eq "\") {
|
||||
if ($i -eq ($argument.Length - 1) -and $current_char -eq "\") {
|
||||
# We are at the end of the string so we need to add the same \
|
||||
# * 2 as the end char would be a "
|
||||
$new_argument += ("\" * ($num_backslashes + 1) * 2)
|
||||
} elseif ($current_char -eq '"') {
|
||||
}
|
||||
elseif ($current_char -eq '"') {
|
||||
# we have a inline ", we need to add the existing \ but * by 2
|
||||
# plus another 1
|
||||
$new_argument += ("\" * (($num_backslashes * 2) + 1))
|
||||
$new_argument += $current_char
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
# normal character so no need to escape the \ we have counted
|
||||
$new_argument += ("\" * $num_backslashes)
|
||||
$new_argument += $current_char
|
||||
|
@ -50,7 +53,7 @@ Function Escape-Argument($argument, $force_quote=$false) {
|
|||
}
|
||||
}
|
||||
|
||||
Function Argv-ToString($arguments, $force_quote=$false) {
|
||||
Function Argv-ToString($arguments, $force_quote = $false) {
|
||||
# Takes in a list of un escaped arguments and convert it to a single string
|
||||
# that can be used when starting a new process. It will escape the
|
||||
# characters as necessary in the list.
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
Function Backup-File {
|
||||
<#
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Helper function to make a backup of a file.
|
||||
.EXAMPLE
|
||||
Backup-File -path $path -WhatIf:$check_mode
|
||||
#>
|
||||
[CmdletBinding(SupportsShouldProcess=$true)]
|
||||
[CmdletBinding(SupportsShouldProcess = $true)]
|
||||
|
||||
Param (
|
||||
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
|
||||
|
@ -21,7 +21,8 @@ Function Backup-File {
|
|||
$backup_path = "$path.$pid." + [DateTime]::Now.ToString("yyyyMMdd-HHmmss") + ".bak";
|
||||
Try {
|
||||
Copy-Item -LiteralPath $path -Destination $backup_path
|
||||
} Catch {
|
||||
}
|
||||
Catch {
|
||||
throw "Failed to create backup file '$backup_path' from '$path'. ($($_.Exception.Message))"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,15 +28,17 @@ Function Convert-ListToSnakeCase($list) {
|
|||
foreach ($value in $list) {
|
||||
if ($value -is [Hashtable]) {
|
||||
$new_value = Convert-DictToSnakeCase -dict $value
|
||||
} elseif ($value -is [Array] -or $value -is [System.Collections.ArrayList]) {
|
||||
}
|
||||
elseif ($value -is [Array] -or $value -is [System.Collections.ArrayList]) {
|
||||
$new_value = Convert-ListToSnakeCase -list $value
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$new_value = $value
|
||||
}
|
||||
[void]$snake_list.Add($new_value)
|
||||
}
|
||||
|
||||
return ,$snake_list
|
||||
return , $snake_list
|
||||
}
|
||||
|
||||
# converts a dict/hashtable keys from camelCase to snake_case
|
||||
|
@ -51,14 +53,16 @@ Function Convert-DictToSnakeCase($dict) {
|
|||
$value = $dict_entry.Value
|
||||
if ($value -is [Hashtable]) {
|
||||
$snake_dict.$snake_key = Convert-DictToSnakeCase -dict $value
|
||||
} elseif ($value -is [Array] -or $value -is [System.Collections.ArrayList]) {
|
||||
}
|
||||
elseif ($value -is [Array] -or $value -is [System.Collections.ArrayList]) {
|
||||
$snake_dict.$snake_key = Convert-ListToSnakeCase -list $value
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$snake_dict.$snake_key = $value
|
||||
}
|
||||
}
|
||||
|
||||
return ,$snake_dict
|
||||
return , $snake_dict
|
||||
}
|
||||
|
||||
# this line must stay at the bottom to ensure all defined module parts are exported
|
||||
|
|
|
@ -8,11 +8,13 @@ Function Load-CommandUtils {
|
|||
.SYNOPSIS
|
||||
No-op, as the C# types are automatically loaded.
|
||||
#>
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification = "Cannot change the name now")]
|
||||
Param()
|
||||
$msg = "Load-CommandUtils is deprecated and no longer needed, this cmdlet will be removed in a future version"
|
||||
if ((Get-Command -Name Add-DeprecationWarning -ErrorAction SilentlyContinue) -and (Get-Variable -Name result -ErrorAction SilentlyContinue)) {
|
||||
Add-DeprecationWarning -obj $result.Value -message $msg -version 2.12
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$module = Get-Variable -Name module -ErrorAction SilentlyContinue
|
||||
if ($null -ne $module -and $module.Value.GetType().FullName -eq "Ansible.Basic.AnsibleModule") {
|
||||
$module.Value.Deprecate($msg, "2.12")
|
||||
|
@ -47,13 +49,15 @@ Function Get-ExecutablePath {
|
|||
|
||||
if ($full_path -ne $executable -and $directory -ne $null) {
|
||||
$file = Get-Item -LiteralPath "$directory\$executable" -Force -ErrorAction SilentlyContinue
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$file = Get-Item -LiteralPath $executable -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
if ($null -ne $file) {
|
||||
$executable_path = $file.FullName
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$executable_path = [Ansible.Process.ProcessUtil]::SearchPath($executable)
|
||||
}
|
||||
return $executable_path
|
||||
|
@ -110,7 +114,7 @@ Function Run-Command {
|
|||
# run the command and get the results
|
||||
$command_result = [Ansible.Process.ProcessUtil]::CreateProcess($executable, $command, $working_directory, $environment, $stdin, $output_encoding_override)
|
||||
|
||||
return ,@{
|
||||
return , @{
|
||||
executable = $executable
|
||||
stdout = $command_result.StandardOut
|
||||
stderr = $command_result.StandardError
|
||||
|
|
|
@ -12,14 +12,16 @@ result from that.
|
|||
Function Test-AnsiblePath {
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(Mandatory=$true)][string]$Path
|
||||
[Parameter(Mandatory = $true)][string]$Path
|
||||
)
|
||||
# Replacement for Test-Path
|
||||
try {
|
||||
$file_attributes = [System.IO.File]::GetAttributes($Path)
|
||||
} catch [System.IO.FileNotFoundException], [System.IO.DirectoryNotFoundException] {
|
||||
}
|
||||
catch [System.IO.FileNotFoundException], [System.IO.DirectoryNotFoundException] {
|
||||
return $false
|
||||
} catch [NotSupportedException] {
|
||||
}
|
||||
catch [NotSupportedException] {
|
||||
# When testing a path like Cert:\LocalMachine\My, System.IO.File will
|
||||
# not work, we just revert back to using Test-Path for this
|
||||
return Test-Path -Path $Path
|
||||
|
@ -27,7 +29,8 @@ Function Test-AnsiblePath {
|
|||
|
||||
if ([Int32]$file_attributes -eq -1) {
|
||||
return $false
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
@ -35,12 +38,13 @@ Function Test-AnsiblePath {
|
|||
Function Get-AnsibleItem {
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(Mandatory=$true)][string]$Path
|
||||
[Parameter(Mandatory = $true)][string]$Path
|
||||
)
|
||||
# Replacement for Get-Item
|
||||
try {
|
||||
$file_attributes = [System.IO.File]::GetAttributes($Path)
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
# if -ErrorAction SilentlyCotinue is set on the cmdlet and we failed to
|
||||
# get the attributes, just return $null, otherwise throw the error
|
||||
if ($ErrorActionPreference -ne "SilentlyContinue") {
|
||||
|
@ -50,9 +54,11 @@ Function Get-AnsibleItem {
|
|||
}
|
||||
if ([Int32]$file_attributes -eq -1) {
|
||||
throw New-Object -TypeName System.Management.Automation.ItemNotFoundException -ArgumentList "Cannot find path '$Path' because it does not exist."
|
||||
} elseif ($file_attributes.HasFlag([System.IO.FileAttributes]::Directory)) {
|
||||
}
|
||||
elseif ($file_attributes.HasFlag([System.IO.FileAttributes]::Directory)) {
|
||||
return New-Object -TypeName System.IO.DirectoryInfo -ArgumentList $Path
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return New-Object -TypeName System.IO.FileInfo -ArgumentList $Path
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
Set-StrictMode -Version 2.0
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Function Set-Attr($obj, $name, $value)
|
||||
{
|
||||
<#
|
||||
Function Set-Attr($obj, $name, $value) {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Helper function to set an "attribute" on a psobject instance in PowerShell.
|
||||
This is a convenience to make adding Members to the object easier and
|
||||
|
@ -16,24 +15,20 @@ Function Set-Attr($obj, $name, $value)
|
|||
#>
|
||||
|
||||
# If the provided $obj is undefined, define one to be nice
|
||||
If (-not $obj.GetType)
|
||||
{
|
||||
If (-not $obj.GetType) {
|
||||
$obj = @{ }
|
||||
}
|
||||
|
||||
Try
|
||||
{
|
||||
Try {
|
||||
$obj.$name = $value
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Catch {
|
||||
$obj | Add-Member -Force -MemberType NoteProperty -Name $name -Value $value
|
||||
}
|
||||
}
|
||||
|
||||
Function Exit-Json($obj)
|
||||
{
|
||||
<#
|
||||
Function Exit-Json($obj) {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Helper function to convert a PowerShell object to JSON and output it, exiting
|
||||
the script
|
||||
|
@ -42,8 +37,7 @@ Function Exit-Json($obj)
|
|||
#>
|
||||
|
||||
# If the provided $obj is undefined, define one to be nice
|
||||
If (-not $obj.GetType)
|
||||
{
|
||||
If (-not $obj.GetType) {
|
||||
$obj = @{ }
|
||||
}
|
||||
|
||||
|
@ -55,9 +49,8 @@ Function Exit-Json($obj)
|
|||
Exit
|
||||
}
|
||||
|
||||
Function Fail-Json($obj, $message = $null)
|
||||
{
|
||||
<#
|
||||
Function Fail-Json($obj, $message = $null) {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Helper function to add the "msg" property and "failed" property, convert the
|
||||
PowerShell Hashtable to JSON and output it, exiting the script
|
||||
|
@ -67,12 +60,14 @@ Function Fail-Json($obj, $message = $null)
|
|||
|
||||
if ($obj -is [hashtable] -or $obj -is [psobject]) {
|
||||
# Nothing to do
|
||||
} elseif ($obj -is [string] -and $null -eq $message) {
|
||||
}
|
||||
elseif ($obj -is [string] -and $null -eq $message) {
|
||||
# If we weren't given 2 args, and the only arg was a string,
|
||||
# create a new Hashtable and use the arg as the failure message
|
||||
$message = $obj
|
||||
$obj = @{ }
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
# If the first argument is undefined or a different type,
|
||||
# make it a Hashtable
|
||||
$obj = @{ }
|
||||
|
@ -90,9 +85,8 @@ Function Fail-Json($obj, $message = $null)
|
|||
Exit 1
|
||||
}
|
||||
|
||||
Function Add-Warning($obj, $message)
|
||||
{
|
||||
<#
|
||||
Function Add-Warning($obj, $message) {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Helper function to add warnings, even if the warnings attribute was
|
||||
not already set up. This is a convenience for the module developer
|
||||
|
@ -101,16 +95,16 @@ Function Add-Warning($obj, $message)
|
|||
|
||||
if (-not $obj.ContainsKey("warnings")) {
|
||||
$obj.warnings = @()
|
||||
} elseif ($obj.warnings -isnot [array]) {
|
||||
}
|
||||
elseif ($obj.warnings -isnot [array]) {
|
||||
throw "Add-Warning: warnings attribute is not an array"
|
||||
}
|
||||
|
||||
$obj.warnings += $message
|
||||
}
|
||||
|
||||
Function Add-DeprecationWarning($obj, $message, $version = $null)
|
||||
{
|
||||
<#
|
||||
Function Add-DeprecationWarning($obj, $message, $version = $null) {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Helper function to add deprecations, even if the deprecations attribute was
|
||||
not already set up. This is a convenience for the module developer
|
||||
|
@ -118,7 +112,8 @@ Function Add-DeprecationWarning($obj, $message, $version = $null)
|
|||
#>
|
||||
if (-not $obj.ContainsKey("deprecations")) {
|
||||
$obj.deprecations = @()
|
||||
} elseif ($obj.deprecations -isnot [array]) {
|
||||
}
|
||||
elseif ($obj.deprecations -isnot [array]) {
|
||||
throw "Add-DeprecationWarning: deprecations attribute is not a list"
|
||||
}
|
||||
|
||||
|
@ -128,23 +123,22 @@ Function Add-DeprecationWarning($obj, $message, $version = $null)
|
|||
}
|
||||
}
|
||||
|
||||
Function Expand-Environment($value)
|
||||
{
|
||||
<#
|
||||
Function Expand-Environment($value) {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Helper function to expand environment variables in values. By default
|
||||
it turns any type to a string, but we ensure $null remains $null.
|
||||
#>
|
||||
if ($null -ne $value) {
|
||||
[System.Environment]::ExpandEnvironmentVariables($value)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$value
|
||||
}
|
||||
}
|
||||
|
||||
Function Get-AnsibleParam($obj, $name, $default = $null, $resultobj = @{}, $failifempty = $false, $emptyattributefailmessage, $ValidateSet, $ValidateSetErrorMessage, $type = $null, $aliases = @())
|
||||
{
|
||||
<#
|
||||
Function Get-AnsibleParam {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Helper function to get an "attribute" from a psobject instance in PowerShell.
|
||||
This is a convenience to make getting Members from an object easier and
|
||||
|
@ -156,6 +150,18 @@ Function Get-AnsibleParam($obj, $name, $default = $null, $resultobj = @{}, $fail
|
|||
Get-AnsibleParam also supports Parameter validation to save you from coding that manually
|
||||
Note that if you use the failifempty option, you do need to specify resultobject as well.
|
||||
#>
|
||||
param (
|
||||
$obj,
|
||||
$name,
|
||||
$default = $null,
|
||||
$resultobj = @{},
|
||||
$failifempty = $false,
|
||||
$emptyattributefailmessage,
|
||||
$ValidateSet,
|
||||
$ValidateSetErrorMessage,
|
||||
$type = $null,
|
||||
$aliases = @()
|
||||
)
|
||||
# Check if the provided Member $name or aliases exist in $obj and return it or the default.
|
||||
try {
|
||||
|
||||
|
@ -180,20 +186,24 @@ Function Get-AnsibleParam($obj, $name, $default = $null, $resultobj = @{}, $fail
|
|||
|
||||
if ($ValidateSet -contains ($obj.$name)) {
|
||||
$value = $obj.$name
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if ($null -eq $ValidateSetErrorMessage) {
|
||||
#Auto-generated error should be sufficient in most use cases
|
||||
$ValidateSetErrorMessage = "Get-AnsibleParam: Argument $name needs to be one of $($ValidateSet -join ",") but was $($obj.$name)."
|
||||
}
|
||||
Fail-Json -obj $resultobj -message $ValidateSetErrorMessage
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$value = $obj.$name
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
if ($failifempty -eq $false) {
|
||||
$value = $default
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (-not $emptyattributefailmessage) {
|
||||
$emptyattributefailmessage = "Get-AnsibleParam: Missing required argument: $name"
|
||||
}
|
||||
|
@ -224,45 +234,51 @@ Function Get-AnsibleParam($obj, $name, $default = $null, $resultobj = @{}, $fail
|
|||
Fail-Json -obj $resultobj -message "Get-AnsibleParam: Parameter '$name' has an invalid path '$value' specified."
|
||||
}
|
||||
}
|
||||
} elseif ($type -eq "str") {
|
||||
}
|
||||
elseif ($type -eq "str") {
|
||||
# Convert str types to real Powershell strings
|
||||
$value = $value.ToString()
|
||||
} elseif ($type -eq "bool") {
|
||||
}
|
||||
elseif ($type -eq "bool") {
|
||||
# Convert boolean types to real Powershell booleans
|
||||
$value = $value | ConvertTo-Bool
|
||||
} elseif ($type -eq "int") {
|
||||
}
|
||||
elseif ($type -eq "int") {
|
||||
# Convert int types to real Powershell integers
|
||||
$value = $value -as [int]
|
||||
} elseif ($type -eq "float") {
|
||||
}
|
||||
elseif ($type -eq "float") {
|
||||
# Convert float types to real Powershell floats
|
||||
$value = $value -as [float]
|
||||
} elseif ($type -eq "list") {
|
||||
}
|
||||
elseif ($type -eq "list") {
|
||||
if ($value -is [array]) {
|
||||
# Nothing to do
|
||||
} elseif ($value -is [string]) {
|
||||
}
|
||||
elseif ($value -is [string]) {
|
||||
# Convert string type to real Powershell array
|
||||
$value = $value.Split(",").Trim()
|
||||
} elseif ($value -is [int]) {
|
||||
}
|
||||
elseif ($value -is [int]) {
|
||||
$value = @($value)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Fail-Json -obj $resultobj -message "Get-AnsibleParam: Parameter '$name' is not a YAML list."
|
||||
}
|
||||
# , is not a typo, forces it to return as a list when it is empty or only has 1 entry
|
||||
return ,$value
|
||||
return , $value
|
||||
}
|
||||
|
||||
return $value
|
||||
}
|
||||
|
||||
#Alias Get-attr-->Get-AnsibleParam for backwards compat. Only add when needed to ease debugging of scripts
|
||||
If (-not(Get-Alias -Name "Get-attr" -ErrorAction SilentlyContinue))
|
||||
{
|
||||
If (-not(Get-Alias -Name "Get-attr" -ErrorAction SilentlyContinue)) {
|
||||
New-Alias -Name Get-attr -Value Get-AnsibleParam
|
||||
}
|
||||
|
||||
Function ConvertTo-Bool
|
||||
{
|
||||
<#
|
||||
Function ConvertTo-Bool {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Helper filter/pipeline function to convert a value to boolean following current
|
||||
Ansible practices
|
||||
|
@ -270,40 +286,43 @@ Function ConvertTo-Bool
|
|||
$is_true = "true" | ConvertTo-Bool
|
||||
#>
|
||||
param(
|
||||
[parameter(valuefrompipeline=$true)]
|
||||
[parameter(valuefrompipeline = $true)]
|
||||
$obj
|
||||
)
|
||||
|
||||
$boolean_strings = "yes", "on", "1", "true", 1
|
||||
$obj_string = [string]$obj
|
||||
process {
|
||||
$boolean_strings = "yes", "on", "1", "true", 1
|
||||
$obj_string = [string]$obj
|
||||
|
||||
if (($obj -is [boolean] -and $obj) -or $boolean_strings -contains $obj_string.ToLower()) {
|
||||
return $true
|
||||
} else {
|
||||
return $false
|
||||
if (($obj -is [boolean] -and $obj) -or $boolean_strings -contains $obj_string.ToLower()) {
|
||||
return $true
|
||||
}
|
||||
else {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Function Parse-Args($arguments, $supports_check_mode = $false)
|
||||
{
|
||||
<#
|
||||
Function Parse-Args {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Helper function to parse Ansible JSON arguments from a "file" passed as
|
||||
the single argument to the module.
|
||||
.EXAMPLE
|
||||
$params = Parse-Args $args
|
||||
#>
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification = "Cannot change the name now")]
|
||||
param ($arguments, $supports_check_mode = $false)
|
||||
|
||||
$params = New-Object psobject
|
||||
If ($arguments.Length -gt 0)
|
||||
{
|
||||
If ($arguments.Length -gt 0) {
|
||||
$params = Get-Content $arguments[0] | ConvertFrom-Json
|
||||
}
|
||||
Else {
|
||||
$params = $complex_args
|
||||
}
|
||||
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
|
||||
If ($check_mode -and -not $supports_check_mode)
|
||||
{
|
||||
If ($check_mode -and -not $supports_check_mode) {
|
||||
Exit-Json @{
|
||||
skipped = $true
|
||||
changed = $false
|
||||
|
@ -314,17 +333,14 @@ Function Parse-Args($arguments, $supports_check_mode = $false)
|
|||
}
|
||||
|
||||
|
||||
Function Get-FileChecksum($path, $algorithm = 'sha1')
|
||||
{
|
||||
<#
|
||||
Function Get-FileChecksum($path, $algorithm = 'sha1') {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Helper function to calculate a hash of a file in a way which PowerShell 3
|
||||
and above can handle
|
||||
#>
|
||||
If (Test-Path -LiteralPath $path -PathType Leaf)
|
||||
{
|
||||
switch ($algorithm)
|
||||
{
|
||||
If (Test-Path -LiteralPath $path -PathType Leaf) {
|
||||
switch ($algorithm) {
|
||||
'md5' { $sp = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider }
|
||||
'sha1' { $sp = New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider }
|
||||
'sha256' { $sp = New-Object -TypeName System.Security.Cryptography.SHA256CryptoServiceProvider }
|
||||
|
@ -336,39 +352,36 @@ Function Get-FileChecksum($path, $algorithm = 'sha1')
|
|||
If ($PSVersionTable.PSVersion.Major -ge 4) {
|
||||
$raw_hash = Get-FileHash -LiteralPath $path -Algorithm $algorithm
|
||||
$hash = $raw_hash.Hash.ToLower()
|
||||
} Else {
|
||||
}
|
||||
Else {
|
||||
$fp = [System.IO.File]::Open($path, [System.IO.Filemode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite);
|
||||
$hash = [System.BitConverter]::ToString($sp.ComputeHash($fp)).Replace("-", "").ToLower();
|
||||
$fp.Dispose();
|
||||
}
|
||||
}
|
||||
ElseIf (Test-Path -LiteralPath $path -PathType Container)
|
||||
{
|
||||
ElseIf (Test-Path -LiteralPath $path -PathType Container) {
|
||||
$hash = "3";
|
||||
}
|
||||
Else
|
||||
{
|
||||
Else {
|
||||
$hash = "1";
|
||||
}
|
||||
return $hash
|
||||
}
|
||||
|
||||
Function Get-PendingRebootStatus
|
||||
{
|
||||
<#
|
||||
Function Get-PendingRebootStatus {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Check if reboot is required, if so notify CA.
|
||||
Function returns true if computer has a pending reboot
|
||||
#>
|
||||
$featureData = Invoke-CimMethod -EA Ignore -Name GetServerFeature -Namespace root\microsoft\windows\servermanager -Class MSFT_ServerManagerTasks
|
||||
$regData = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" "PendingFileRenameOperations" -EA Ignore
|
||||
$CBSRebootStatus = Get-ChildItem "HKLM:\\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing" -ErrorAction SilentlyContinue| Where-Object {$_.PSChildName -eq "RebootPending"}
|
||||
if(($featureData -and $featureData.RequiresReboot) -or $regData -or $CBSRebootStatus)
|
||||
{
|
||||
$CBSRebootStatus = Get-ChildItem "HKLM:\\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing" -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.PSChildName -eq "RebootPending" }
|
||||
if (($featureData -and $featureData.RequiresReboot) -or $regData -or $CBSRebootStatus) {
|
||||
return $True
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
return $False
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
|
||||
#Requires -Module Ansible.ModuleUtils.PrivilegeUtil
|
||||
|
||||
Function Load-LinkUtils() {
|
||||
Function Load-LinkUtils {
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification = "Cannot change the name now")]
|
||||
param ()
|
||||
|
||||
$link_util = @'
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using System;
|
||||
|
@ -314,8 +317,12 @@ namespace Ansible
|
|||
throw new Exception(errorMessage);
|
||||
}
|
||||
|
||||
string printName = new string(buffer.PathBuffer, (int)(buffer.PrintNameOffset / SIZE_OF_WCHAR) + pathOffset, (int)(buffer.PrintNameLength / SIZE_OF_WCHAR));
|
||||
string substituteName = new string(buffer.PathBuffer, (int)(buffer.SubstituteNameOffset / SIZE_OF_WCHAR) + pathOffset, (int)(buffer.SubstituteNameLength / SIZE_OF_WCHAR));
|
||||
string printName = new string(buffer.PathBuffer,
|
||||
(int)(buffer.PrintNameOffset / SIZE_OF_WCHAR) + pathOffset,
|
||||
(int)(buffer.PrintNameLength / SIZE_OF_WCHAR));
|
||||
string substituteName = new string(buffer.PathBuffer,
|
||||
(int)(buffer.SubstituteNameOffset / SIZE_OF_WCHAR) + pathOffset,
|
||||
(int)(buffer.SubstituteNameLength / SIZE_OF_WCHAR));
|
||||
|
||||
// TODO: should we check for \?\UNC\server for convert it to the NT style \\server path
|
||||
// Remove the leading Windows object directory \?\ from the path if present
|
||||
|
@ -432,7 +439,7 @@ Function New-Link($link_path, $link_target, $link_type) {
|
|||
throw "link_target '$link_target' does not exist, cannot create link"
|
||||
}
|
||||
|
||||
switch($link_type) {
|
||||
switch ($link_type) {
|
||||
"link" {
|
||||
$type = [Ansible.LinkType]::SymbolicLink
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@ Function Import-PrivilegeUtil {
|
|||
$msg = "Import-PrivilegeUtil is deprecated and no longer needed, this cmdlet will be removed in a future version"
|
||||
if ((Get-Command -Name Add-DeprecationWarning -ErrorAction SilentlyContinue) -and (Get-Variable -Name result -ErrorAction SilentlyContinue)) {
|
||||
Add-DeprecationWarning -obj $result.Value -message $msg -version 2.12
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$module = Get-Variable -Name module -ErrorAction SilentlyContinue
|
||||
if ($null -ne $module -and $module.Value.GetType().FullName -eq "Ansible.Basic.AnsibleModule") {
|
||||
$module.Value.Deprecate($msg, "2.12")
|
||||
|
@ -37,7 +38,7 @@ Function Get-AnsiblePrivilege {
|
|||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][String]$Name
|
||||
[Parameter(Mandatory = $true)][String]$Name
|
||||
)
|
||||
|
||||
if (-not [Ansible.Privilege.PrivilegeUtil]::CheckPrivilegeName($Name)) {
|
||||
|
@ -49,7 +50,8 @@ Function Get-AnsiblePrivilege {
|
|||
if ($privilege_info.ContainsKey($Name)) {
|
||||
$status = $privilege_info.$Name
|
||||
return $status.HasFlag([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
@ -70,11 +72,11 @@ Function Set-AnsiblePrivilege {
|
|||
#>
|
||||
[CmdletBinding(SupportsShouldProcess)]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][String]$Name,
|
||||
[Parameter(Mandatory=$true)][bool]$Value
|
||||
[Parameter(Mandatory = $true)][String]$Name,
|
||||
[Parameter(Mandatory = $true)][bool]$Value
|
||||
)
|
||||
|
||||
$action = switch($Value) {
|
||||
$action = switch ($Value) {
|
||||
$true { "Enable" }
|
||||
$false { "Disable" }
|
||||
}
|
||||
|
@ -82,7 +84,8 @@ Function Set-AnsiblePrivilege {
|
|||
$current_state = Get-AnsiblePrivilege -Name $Name
|
||||
if ($current_state -eq $Value) {
|
||||
return # no change needs to occur
|
||||
} elseif ($null -eq $current_state) {
|
||||
}
|
||||
elseif ($null -eq $current_state) {
|
||||
# once a privilege is removed from a token we cannot do anything with it
|
||||
throw [System.InvalidOperationException] "Cannot $($action.ToLower()) the privilege '$Name' as it has been removed from the token"
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@ Function Convert-FromSID($sid) {
|
|||
$account_object = New-Object System.Security.Principal.SecurityIdentifier($sid)
|
||||
try {
|
||||
$nt_account = $account_object.Translate([System.Security.Principal.NTAccount])
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
Fail-Json -obj @{} -message "failed to convert sid '$sid' to a logon name: $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
|
@ -17,7 +18,8 @@ Function Convert-FromSID($sid) {
|
|||
}
|
||||
|
||||
Function Convert-ToSID {
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingEmptyCatchBlock", "", Justification="We don't care if converting to a SID fails, just that it failed or not")]
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingEmptyCatchBlock", "",
|
||||
Justification = "We don't care if converting to a SID fails, just that it failed or not")]
|
||||
param($account_name)
|
||||
# Converts an account name to a SID, it can take in the following forms
|
||||
# SID: Will just return the SID value that was passed in
|
||||
|
@ -34,21 +36,25 @@ Function Convert-ToSID {
|
|||
try {
|
||||
$sid = New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList $account_name
|
||||
return $sid.Value
|
||||
} catch {}
|
||||
}
|
||||
catch {}
|
||||
|
||||
if ($account_name -like "*\*") {
|
||||
$account_name_split = $account_name -split "\\"
|
||||
if ($account_name_split[0] -eq ".") {
|
||||
$domain = $env:COMPUTERNAME
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$domain = $account_name_split[0]
|
||||
}
|
||||
$username = $account_name_split[1]
|
||||
} elseif ($account_name -like "*@*") {
|
||||
}
|
||||
elseif ($account_name -like "*@*") {
|
||||
$account_name_split = $account_name -split "@"
|
||||
$domain = $account_name_split[1]
|
||||
$username = $account_name_split[0]
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$domain = $null
|
||||
$username = $account_name
|
||||
}
|
||||
|
@ -59,15 +65,18 @@ Function Convert-ToSID {
|
|||
if ($domain -eq $env:COMPUTERNAME) {
|
||||
$adsi = [ADSI]("WinNT://$env:COMPUTERNAME,computer")
|
||||
$group = $adsi.psbase.children | Where-Object { $_.schemaClassName -eq "group" -and $_.Name -eq $username }
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$group = $null
|
||||
}
|
||||
if ($group) {
|
||||
$account = New-Object System.Security.Principal.NTAccount($username)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$account = New-Object System.Security.Principal.NTAccount($domain, $username)
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
# when in a domain NTAccount(String) will favour domain lookups check
|
||||
# if username is a local user and explictly search on the localhost for
|
||||
# that account
|
||||
|
@ -75,14 +84,16 @@ Function Convert-ToSID {
|
|||
$user = $adsi.psbase.children | Where-Object { $_.schemaClassName -eq "user" -and $_.Name -eq $username }
|
||||
if ($user) {
|
||||
$account = New-Object System.Security.Principal.NTAccount($env:COMPUTERNAME, $username)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$account = New-Object System.Security.Principal.NTAccount($username)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$account_sid = $account.Translate([System.Security.Principal.SecurityIdentifier])
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
Fail-Json @{} "account_name $account_name is not a valid account, cannot get SID: $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
|
|
|
@ -214,11 +214,13 @@ Function Get-AnsibleWebRequest {
|
|||
|
||||
if ($UseDefaultCredential -and $web_request -is [System.Net.HttpWebRequest]) {
|
||||
$web_request.UseDefaultCredentials = $true
|
||||
} elseif ($UrlUsername) {
|
||||
}
|
||||
elseif ($UrlUsername) {
|
||||
if ($ForceBasicAuth) {
|
||||
$auth_value = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $UrlUsername, $UrlPassword)))
|
||||
$web_request.Headers.Add("Authorization", "Basic $auth_value")
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$credential = New-Object -TypeName System.Net.NetworkCredential -ArgumentList $UrlUsername, $UrlPassword
|
||||
$web_request.Credentials = $credential
|
||||
}
|
||||
|
@ -238,7 +240,8 @@ Function Get-AnsibleWebRequest {
|
|||
$cert = New-Object -TypeName "$crypto_ns.X509Certificate2" -ArgumentList @(
|
||||
$ClientCert, $ClientCertPassword
|
||||
)
|
||||
} catch [System.Security.Cryptography.CryptographicException] {
|
||||
}
|
||||
catch [System.Security.Cryptography.CryptographicException] {
|
||||
Write-Error -Message "Failed to read client certificate at '$ClientCert'" -Exception $_.Exception -Category SecurityError
|
||||
return
|
||||
}
|
||||
|
@ -250,9 +253,11 @@ Function Get-AnsibleWebRequest {
|
|||
|
||||
if (-not $UseProxy) {
|
||||
$proxy = $null
|
||||
} elseif ($ProxyUrl) {
|
||||
}
|
||||
elseif ($ProxyUrl) {
|
||||
$proxy = New-Object -TypeName System.Net.WebProxy -ArgumentList $ProxyUrl, $true
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$proxy = $web_request.Proxy
|
||||
}
|
||||
|
||||
|
@ -264,11 +269,13 @@ Function Get-AnsibleWebRequest {
|
|||
# property. We cannot set UseDefaultCredentials so we just set the Credentials to the
|
||||
# DefaultCredentials in the CredentialCache which does the same thing.
|
||||
$proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
|
||||
} elseif ($ProxyUsername) {
|
||||
}
|
||||
elseif ($ProxyUsername) {
|
||||
$proxy.Credentials = New-Object -TypeName System.Net.NetworkCredential -ArgumentList @(
|
||||
$ProxyUsername, $ProxyPassword
|
||||
)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$proxy.Credentials = $null
|
||||
}
|
||||
}
|
||||
|
@ -305,7 +312,8 @@ Function Get-AnsibleWebRequest {
|
|||
if ($Headers -and $Headers.ContainsKey("User-Agent")) {
|
||||
if ($HttpAgent -eq $ansible_web_request_options.http_agent.default) {
|
||||
$HttpAgent = $Headers['User-Agent']
|
||||
} elseif ($null -ne $Module) {
|
||||
}
|
||||
elseif ($null -ne $Module) {
|
||||
$Module.Warn("The 'User-Agent' header and the 'http_agent' was set, using the 'http_agent' for web request")
|
||||
}
|
||||
}
|
||||
|
@ -316,7 +324,8 @@ Function Get-AnsibleWebRequest {
|
|||
safe {
|
||||
if ($web_request.Method -in @("GET", "HEAD")) {
|
||||
$web_request.AllowAutoRedirect = $true
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$web_request.AllowAutoRedirect = $false
|
||||
}
|
||||
}
|
||||
|
@ -325,7 +334,8 @@ Function Get-AnsibleWebRequest {
|
|||
|
||||
if ($MaximumRedirection -eq 0) {
|
||||
$web_request.AllowAutoRedirect = $false
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$web_request.MaximumAutomaticRedirections = $MaximumRedirection
|
||||
}
|
||||
}
|
||||
|
@ -388,16 +398,16 @@ Function Invoke-WithWebRequest {
|
|||
#>
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[Parameter(Mandatory = $true)]
|
||||
[System.Object]
|
||||
[ValidateScript({ $_.GetType().FullName -eq 'Ansible.Basic.AnsibleModule' })]
|
||||
$Module,
|
||||
|
||||
[Parameter(Mandatory=$true)]
|
||||
[Parameter(Mandatory = $true)]
|
||||
[System.Net.WebRequest]
|
||||
$Request,
|
||||
|
||||
[Parameter(Mandatory=$true)]
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ScriptBlock]
|
||||
$Script,
|
||||
|
||||
|
@ -415,7 +425,8 @@ Function Invoke-WithWebRequest {
|
|||
try {
|
||||
$Body.CopyTo($request_st)
|
||||
$request_st.Flush()
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
$request_st.Close()
|
||||
}
|
||||
}
|
||||
|
@ -423,7 +434,8 @@ Function Invoke-WithWebRequest {
|
|||
try {
|
||||
try {
|
||||
$web_response = $Request.GetResponse()
|
||||
} catch [System.Net.WebException] {
|
||||
}
|
||||
catch [System.Net.WebException] {
|
||||
# A WebResponse with a status code not in the 200 range will raise a WebException. We check if the
|
||||
# exception raised contains the actual response and continue on if IgnoreBadResponse is set. We also
|
||||
# make sure we set the status_code return value on the Module object if possible
|
||||
|
@ -436,7 +448,8 @@ Function Invoke-WithWebRequest {
|
|||
$Module.Result.status_code = $_.Exception.Response.StatusCode
|
||||
throw $_
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
throw $_
|
||||
}
|
||||
}
|
||||
|
@ -445,7 +458,8 @@ Function Invoke-WithWebRequest {
|
|||
# A FileWebResponse won't have these properties set
|
||||
$Module.Result.msg = "OK"
|
||||
$Module.Result.status_code = 200
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$Module.Result.msg = $web_response.StatusDescription
|
||||
$Module.Result.status_code = $web_response.StatusCode
|
||||
}
|
||||
|
@ -454,10 +468,12 @@ Function Invoke-WithWebRequest {
|
|||
try {
|
||||
# Invoke the ScriptBlock and pass in WebResponse and ResponseStream
|
||||
&$Script -Response $web_response -Stream $response_stream
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
$response_stream.Dispose()
|
||||
}
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
if ($web_response) {
|
||||
$web_response.Close()
|
||||
}
|
||||
|
@ -483,28 +499,28 @@ Function Get-AnsibleWebRequestSpec {
|
|||
# Kept here for backwards compat as this variable was added in Ansible 2.9. Ultimately this util should be removed
|
||||
# once the deprecation period has been added.
|
||||
$ansible_web_request_options = @{
|
||||
method = @{ type="str" }
|
||||
follow_redirects = @{ type="str"; choices=@("all","none","safe"); default="safe" }
|
||||
headers = @{ type="dict" }
|
||||
http_agent = @{ type="str"; default="ansible-httpget" }
|
||||
maximum_redirection = @{ type="int"; default=50 }
|
||||
timeout = @{ type="int"; default=30 } # Was defaulted to 10 in win_get_url but 30 in win_uri so we use 30
|
||||
validate_certs = @{ type="bool"; default=$true }
|
||||
method = @{ type = "str" }
|
||||
follow_redirects = @{ type = "str"; choices = @("all", "none", "safe"); default = "safe" }
|
||||
headers = @{ type = "dict" }
|
||||
http_agent = @{ type = "str"; default = "ansible-httpget" }
|
||||
maximum_redirection = @{ type = "int"; default = 50 }
|
||||
timeout = @{ type = "int"; default = 30 } # Was defaulted to 10 in win_get_url but 30 in win_uri so we use 30
|
||||
validate_certs = @{ type = "bool"; default = $true }
|
||||
|
||||
# Credential options
|
||||
client_cert = @{ type="str" }
|
||||
client_cert_password = @{ type="str"; no_log=$true }
|
||||
force_basic_auth = @{ type="bool"; default=$false }
|
||||
url_username = @{ type="str" }
|
||||
url_password = @{ type="str"; no_log=$true }
|
||||
use_default_credential = @{ type="bool"; default=$false }
|
||||
client_cert = @{ type = "str" }
|
||||
client_cert_password = @{ type = "str"; no_log = $true }
|
||||
force_basic_auth = @{ type = "bool"; default = $false }
|
||||
url_username = @{ type = "str" }
|
||||
url_password = @{ type = "str"; no_log = $true }
|
||||
use_default_credential = @{ type = "bool"; default = $false }
|
||||
|
||||
# Proxy options
|
||||
use_proxy = @{ type="bool"; default=$true }
|
||||
proxy_url = @{ type="str" }
|
||||
proxy_username = @{ type="str" }
|
||||
proxy_password = @{ type="str"; no_log=$true }
|
||||
proxy_use_default_credential = @{ type="bool"; default=$false }
|
||||
use_proxy = @{ type = "bool"; default = $true }
|
||||
proxy_url = @{ type = "str" }
|
||||
proxy_username = @{ type = "str" }
|
||||
proxy_password = @{ type = "str"; no_log = $true }
|
||||
proxy_use_default_credential = @{ type = "bool"; default = $false }
|
||||
}
|
||||
|
||||
$export_members = @{
|
||||
|
|
|
@ -8,7 +8,7 @@ Function Get-PSUtilSpec {
|
|||
#>
|
||||
@{
|
||||
options = @{
|
||||
option1 = @{ type = 'str'; required = $true; aliases = 'alias1' }
|
||||
option1 = @{ type = 'str'; required = $true; aliases = 'alias1' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
$spec = @{
|
||||
options = @{
|
||||
my_opt = @{ type = "str"; required = $true }
|
||||
my_opt = @{ type = "str"; required = $true }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#!powershell
|
||||
|
||||
$res = @{
|
||||
changed = $false
|
||||
source = "user"
|
||||
msg = "hi from selfcontained.ps1"
|
||||
changed = $false
|
||||
source = "user"
|
||||
msg = "hi from selfcontained.ps1"
|
||||
}
|
||||
|
||||
ConvertTo-Json $res
|
|
@ -15,38 +15,41 @@ $module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
|
|||
$test_username = $module.Params.test_username
|
||||
$test_password = $module.Params.test_password
|
||||
|
||||
Function Assert-Equals {
|
||||
Function Assert-Equal {
|
||||
param(
|
||||
[Parameter(Mandatory=$true, ValueFromPipeline=$true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory=$true, Position=0)][AllowNull()]$Expected
|
||||
[Parameter(Mandatory = $true, ValueFromPipeline = $true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory = $true, Position = 0)][AllowNull()]$Expected
|
||||
)
|
||||
|
||||
$matched = $false
|
||||
if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array]) {
|
||||
$Actual.Count | Assert-Equals -Expected $Expected.Count
|
||||
for ($i = 0; $i -lt $Actual.Count; $i++) {
|
||||
$actual_value = $Actual[$i]
|
||||
$expected_value = $Expected[$i]
|
||||
Assert-Equals -Actual $actual_value -Expected $expected_value
|
||||
process {
|
||||
$matched = $false
|
||||
if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array]) {
|
||||
$Actual.Count | Assert-Equal -Expected $Expected.Count
|
||||
for ($i = 0; $i -lt $Actual.Count; $i++) {
|
||||
$actual_value = $Actual[$i]
|
||||
$expected_value = $Expected[$i]
|
||||
Assert-Equal -Actual $actual_value -Expected $expected_value
|
||||
}
|
||||
$matched = $true
|
||||
}
|
||||
$matched = $true
|
||||
} else {
|
||||
$matched = $Actual -ceq $Expected
|
||||
}
|
||||
|
||||
if (-not $matched) {
|
||||
if ($Actual -is [PSObject]) {
|
||||
$Actual = $Actual.ToString()
|
||||
else {
|
||||
$matched = $Actual -ceq $Expected
|
||||
}
|
||||
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.test = $test
|
||||
$module.Result.actual = $Actual
|
||||
$module.Result.expected = $Expected
|
||||
$module.Result.line = $call_stack.ScriptLineNumber
|
||||
$module.Result.method = $call_stack.Position.Text
|
||||
if (-not $matched) {
|
||||
if ($Actual -is [PSObject]) {
|
||||
$Actual = $Actual.ToString()
|
||||
}
|
||||
|
||||
$module.FailJson("AssertionError: actual != expected")
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.test = $test
|
||||
$module.Result.actual = $Actual
|
||||
$module.Result.expected = $Expected
|
||||
$module.Result.line = $call_stack.ScriptLineNumber
|
||||
$module.Result.method = $call_stack.Position.Text
|
||||
|
||||
$module.FailJson("AssertionError: actual != expected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,15 +61,16 @@ $tests = [Ordered]@{
|
|||
|
||||
$h_token = [Ansible.AccessToken.TokenUtil]::OpenProcessToken($h_process, "Query")
|
||||
try {
|
||||
$h_token.IsClosed | Assert-Equals -Expected $false
|
||||
$h_token.IsInvalid | Assert-Equals -Expected $false
|
||||
$h_token.IsClosed | Assert-Equal -Expected $false
|
||||
$h_token.IsInvalid | Assert-Equal -Expected $false
|
||||
|
||||
$actual_user = [Ansible.AccessToken.TokenUtil]::GetTokenUser($h_token)
|
||||
$actual_user | Assert-Equals -Expected $current_user
|
||||
} finally {
|
||||
$actual_user | Assert-Equal -Expected $current_user
|
||||
}
|
||||
finally {
|
||||
$h_token.Dispose()
|
||||
}
|
||||
$h_token.IsClosed | Assert-Equals -Expected $true
|
||||
$h_token.IsClosed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"Open process token of another process" = {
|
||||
|
@ -74,21 +78,24 @@ $tests = [Ordered]@{
|
|||
try {
|
||||
$h_process = [Ansible.AccessToken.TokenUtil]::OpenProcess($proc_info.Id, "QueryInformation", $false)
|
||||
try {
|
||||
$h_process.IsClosed | Assert-Equals -Expected $false
|
||||
$h_process.IsInvalid | Assert-Equals -Expected $false
|
||||
$h_process.IsClosed | Assert-Equal -Expected $false
|
||||
$h_process.IsInvalid | Assert-Equal -Expected $false
|
||||
|
||||
$h_token = [Ansible.AccessToken.TokenUtil]::OpenProcessToken($h_process, "Query")
|
||||
try {
|
||||
$actual_user = [Ansible.AccessToken.TokenUtil]::GetTokenUser($h_token)
|
||||
$actual_user | Assert-Equals -Expected $current_user
|
||||
} finally {
|
||||
$actual_user | Assert-Equal -Expected $current_user
|
||||
}
|
||||
finally {
|
||||
$h_token.Dispose()
|
||||
}
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
$h_process.Dispose()
|
||||
}
|
||||
$h_process.IsClosed | Assert-Equals -Expected $true
|
||||
} finally {
|
||||
$h_process.IsClosed | Assert-Equal -Expected $true
|
||||
}
|
||||
finally {
|
||||
$proc_info | Stop-Process
|
||||
}
|
||||
}
|
||||
|
@ -98,11 +105,13 @@ $tests = [Ordered]@{
|
|||
try {
|
||||
$h_process = [Ansible.AccessToken.TokenUtil]::OpenProcess(4, "QueryInformation", $false)
|
||||
$h_process.Dispose() # Incase this doesn't fail, make sure we still dispose of it
|
||||
} catch [Ansible.AccessToken.Win32Exception] {
|
||||
$failed = $true
|
||||
$_.Exception.Message | Assert-Equals -Expected "Failed to open process 4 with access QueryInformation (Access is denied, Win32ErrorCode 5 - 0x00000005)"
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
catch [Ansible.AccessToken.Win32Exception] {
|
||||
$failed = $true
|
||||
$msg = "Failed to open process 4 with access QueryInformation (Access is denied, Win32ErrorCode 5 - 0x00000005)"
|
||||
$_.Exception.Message | Assert-Equal -Expected $msg
|
||||
}
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"Duplicate access token primary" = {
|
||||
|
@ -111,22 +120,24 @@ $tests = [Ordered]@{
|
|||
try {
|
||||
$dup_token = [Ansible.AccessToken.TokenUtil]::DuplicateToken($h_token, "Query", "Anonymous", "Primary")
|
||||
try {
|
||||
$dup_token.IsClosed | Assert-Equals -Expected $false
|
||||
$dup_token.IsInvalid | Assert-Equals -Expected $false
|
||||
$dup_token.IsClosed | Assert-Equal -Expected $false
|
||||
$dup_token.IsInvalid | Assert-Equal -Expected $false
|
||||
|
||||
$actual_user = [Ansible.AccessToken.TokenUtil]::GetTokenUser($dup_token)
|
||||
|
||||
$actual_user | Assert-Equals -Expected $current_user
|
||||
$actual_user | Assert-Equal -Expected $current_user
|
||||
$actual_stat = [Ansible.AccessToken.TokenUtil]::GetTokenStatistics($dup_token)
|
||||
|
||||
$actual_stat.TokenType | Assert-Equals -Expected ([Ansible.AccessToken.TokenType]::Primary)
|
||||
$actual_stat.ImpersonationLevel | Assert-Equals -Expected ([Ansible.AccessToken.SecurityImpersonationLevel]::Anonymous)
|
||||
} finally {
|
||||
$actual_stat.TokenType | Assert-Equal -Expected ([Ansible.AccessToken.TokenType]::Primary)
|
||||
$actual_stat.ImpersonationLevel | Assert-Equal -Expected ([Ansible.AccessToken.SecurityImpersonationLevel]::Anonymous)
|
||||
}
|
||||
finally {
|
||||
$dup_token.Dispose()
|
||||
}
|
||||
|
||||
$dup_token.IsClosed | Assert-Equals -Expected $true
|
||||
} finally {
|
||||
$dup_token.IsClosed | Assert-Equal -Expected $true
|
||||
}
|
||||
finally {
|
||||
$h_token.Dispose()
|
||||
}
|
||||
}
|
||||
|
@ -140,16 +151,18 @@ $tests = [Ordered]@{
|
|||
try {
|
||||
$actual_user = [Ansible.AccessToken.TokenUtil]::GetTokenUser($dup_token)
|
||||
|
||||
$actual_user | Assert-Equals -Expected $current_user
|
||||
$actual_user | Assert-Equal -Expected $current_user
|
||||
$actual_stat = [Ansible.AccessToken.TokenUtil]::GetTokenStatistics($dup_token)
|
||||
|
||||
$actual_stat.TokenType | Assert-Equals -Expected ([Ansible.AccessToken.TokenType]::Impersonation)
|
||||
$actual_stat.ImpersonationLevel | Assert-Equals -Expected ([Ansible.AccessToken.SecurityImpersonationLevel]"$_")
|
||||
} finally {
|
||||
$actual_stat.TokenType | Assert-Equal -Expected ([Ansible.AccessToken.TokenType]::Impersonation)
|
||||
$actual_stat.ImpersonationLevel | Assert-Equal -Expected ([Ansible.AccessToken.SecurityImpersonationLevel]"$_")
|
||||
}
|
||||
finally {
|
||||
$dup_token.Dispose()
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
$h_token.Dispose()
|
||||
}
|
||||
}
|
||||
|
@ -162,25 +175,26 @@ $tests = [Ordered]@{
|
|||
$tested = $false
|
||||
foreach ($h_token in [Ansible.AccessToken.TokenUtil]::EnumerateUserTokens($system_sid, "Duplicate, Impersonate, Query")) {
|
||||
$actual_user = [Ansible.AccessToken.TokenUtil]::GetTokenUser($h_token)
|
||||
$actual_user | Assert-Equals -Expected $system_sid
|
||||
$actual_user | Assert-Equal -Expected $system_sid
|
||||
|
||||
[Ansible.AccessToken.TokenUtil]::ImpersonateToken($h_token)
|
||||
try {
|
||||
$current_sid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User
|
||||
$current_sid | Assert-Equals -Expected $system_sid
|
||||
} finally {
|
||||
$current_sid | Assert-Equal -Expected $system_sid
|
||||
}
|
||||
finally {
|
||||
[Ansible.AccessToken.TokenUtil]::RevertToSelf()
|
||||
}
|
||||
|
||||
$current_sid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User
|
||||
$current_sid | Assert-Equals -Expected $current_user
|
||||
$current_sid | Assert-Equal -Expected $current_user
|
||||
|
||||
# Will keep on looping for each SYSTEM token it can retrieve, we only want to test 1
|
||||
$tested = $true
|
||||
break
|
||||
}
|
||||
|
||||
$tested | Assert-Equals -Expected $true
|
||||
$tested | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"Get token privileges" = {
|
||||
|
@ -191,8 +205,8 @@ $tests = [Ordered]@{
|
|||
$actual_privs = [Ansible.AccessToken.Tokenutil]::GetTokenPrivileges($h_token)
|
||||
$actual_stat = [Ansible.AccessToken.TokenUtil]::GetTokenStatistics($h_token)
|
||||
|
||||
$actual_privs.Count | Assert-Equals -Expected $priv_info.Count
|
||||
$actual_privs.Count | Assert-Equals -Expected $actual_stat.PrivilegeCount
|
||||
$actual_privs.Count | Assert-Equal -Expected $priv_info.Count
|
||||
$actual_privs.Count | Assert-Equal -Expected $actual_stat.PrivilegeCount
|
||||
|
||||
foreach ($info in $priv_info) {
|
||||
$info_split = $info.Split(" ", [System.StringSplitOptions]::RemoveEmptyEntries)
|
||||
|
@ -200,14 +214,16 @@ $tests = [Ordered]@{
|
|||
$priv_enabled = $info_split[-1] -eq "Enabled"
|
||||
$actual_priv = $actual_privs | Where-Object { $_.Name -eq $priv_name }
|
||||
|
||||
$actual_priv -eq $null | Assert-Equals -Expected $false
|
||||
$actual_priv -eq $null | Assert-Equal -Expected $false
|
||||
if ($priv_enabled) {
|
||||
$actual_priv.Attributes.HasFlag([Ansible.AccessToken.PrivilegeAttributes]::Enabled) | Assert-Equals -Expected $true
|
||||
} else {
|
||||
$actual_priv.Attributes.HasFlag([Ansible.AccessToken.PrivilegeAttributes]::Disabled) | Assert-Equals -Expected $true
|
||||
$actual_priv.Attributes.HasFlag([Ansible.AccessToken.PrivilegeAttributes]::Enabled) | Assert-Equal -Expected $true
|
||||
}
|
||||
else {
|
||||
$actual_priv.Attributes.HasFlag([Ansible.AccessToken.PrivilegeAttributes]::Disabled) | Assert-Equal -Expected $true
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
$h_token.Dispose()
|
||||
}
|
||||
}
|
||||
|
@ -219,25 +235,27 @@ $tests = [Ordered]@{
|
|||
$actual_priv = [Ansible.AccessToken.Tokenutil]::GetTokenPrivileges($h_token)
|
||||
$actual_stat = [Ansible.AccessToken.TokenUtil]::GetTokenStatistics($h_token)
|
||||
|
||||
$actual_stat.TokenId.GetType().FullName | Assert-Equals -Expected "Ansible.AccessToken.Luid"
|
||||
$actual_stat.AuthenticationId.GetType().FullName | Assert-Equals -Expected "Ansible.AccessToken.Luid"
|
||||
$actual_stat.ExpirationTime.GetType().FullName | Assert-Equals -Expected "System.Int64"
|
||||
$actual_stat.TokenId.GetType().FullName | Assert-Equal -Expected "Ansible.AccessToken.Luid"
|
||||
$actual_stat.AuthenticationId.GetType().FullName | Assert-Equal -Expected "Ansible.AccessToken.Luid"
|
||||
$actual_stat.ExpirationTime.GetType().FullName | Assert-Equal -Expected "System.Int64"
|
||||
|
||||
$actual_stat.TokenType | Assert-Equals -Expected ([Ansible.AccessToken.TokenType]::Primary)
|
||||
$actual_stat.TokenType | Assert-Equal -Expected ([Ansible.AccessToken.TokenType]::Primary)
|
||||
|
||||
$os_version = [Version](Get-Item -LiteralPath $env:SystemRoot\System32\kernel32.dll).VersionInfo.ProductVersion
|
||||
if ($os_version -lt [Version]"6.1") {
|
||||
# While the token is a primary token, Server 2008 reports the SecurityImpersonationLevel for a primary token as Impersonation
|
||||
$actual_stat.ImpersonationLevel | Assert-Equals -Expected ([Ansible.AccessToken.SecurityImpersonationLevel]::Impersonation)
|
||||
} else {
|
||||
$actual_stat.ImpersonationLevel | Assert-Equals -Expected ([Ansible.AccessToken.SecurityImpersonationLevel]::Anonymous)
|
||||
$actual_stat.ImpersonationLevel | Assert-Equal -Expected ([Ansible.AccessToken.SecurityImpersonationLevel]::Impersonation)
|
||||
}
|
||||
$actual_stat.DynamicCharged.GetType().FullName | Assert-Equals -Expected "System.UInt32"
|
||||
$actual_stat.DynamicAvailable.GetType().FullName | Assert-Equals -Expected "System.UInt32"
|
||||
$actual_stat.GroupCount.GetType().FullName | Assert-Equals -Expected "System.UInt32"
|
||||
$actual_stat.PrivilegeCount | Assert-Equals -Expected $actual_priv.Count
|
||||
$actual_stat.ModifiedId.GetType().FullName | Assert-Equals -Expected "Ansible.AccessToken.Luid"
|
||||
} finally {
|
||||
else {
|
||||
$actual_stat.ImpersonationLevel | Assert-Equal -Expected ([Ansible.AccessToken.SecurityImpersonationLevel]::Anonymous)
|
||||
}
|
||||
$actual_stat.DynamicCharged.GetType().FullName | Assert-Equal -Expected "System.UInt32"
|
||||
$actual_stat.DynamicAvailable.GetType().FullName | Assert-Equal -Expected "System.UInt32"
|
||||
$actual_stat.GroupCount.GetType().FullName | Assert-Equal -Expected "System.UInt32"
|
||||
$actual_stat.PrivilegeCount | Assert-Equal -Expected $actual_priv.Count
|
||||
$actual_stat.ModifiedId.GetType().FullName | Assert-Equal -Expected "Ansible.AccessToken.Luid"
|
||||
}
|
||||
finally {
|
||||
$h_token.Dispose()
|
||||
}
|
||||
}
|
||||
|
@ -246,23 +264,25 @@ $tests = [Ordered]@{
|
|||
$h_token = [Ansible.AccessToken.TokenUtil]::LogonUser($test_username, $null, $test_password, "Interactive", "Default")
|
||||
try {
|
||||
$actual_elevation_type = [Ansible.AccessToken.TokenUtil]::GetTokenElevationType($h_token)
|
||||
$actual_elevation_type | Assert-Equals -Expected ([Ansible.AccessToken.TokenElevationType]::Limited)
|
||||
$actual_elevation_type | Assert-Equal -Expected ([Ansible.AccessToken.TokenElevationType]::Limited)
|
||||
|
||||
$actual_linked = [Ansible.AccessToken.TokenUtil]::GetTokenLinkedToken($h_token)
|
||||
try {
|
||||
$actual_linked.IsClosed | Assert-Equals -Expected $false
|
||||
$actual_linked.IsInvalid | Assert-Equals -Expected $false
|
||||
$actual_linked.IsClosed | Assert-Equal -Expected $false
|
||||
$actual_linked.IsInvalid | Assert-Equal -Expected $false
|
||||
|
||||
$actual_elevation_type = [Ansible.AccessToken.TokenUtil]::GetTokenElevationType($actual_linked)
|
||||
$actual_elevation_type | Assert-Equals -Expected ([Ansible.AccessToken.TokenElevationType]::Full)
|
||||
$actual_elevation_type | Assert-Equal -Expected ([Ansible.AccessToken.TokenElevationType]::Full)
|
||||
|
||||
$actual_stat = [Ansible.AccessToken.TokenUtil]::GetTokenStatistics($actual_linked)
|
||||
$actual_stat.TokenType | Assert-Equals -Expected ([Ansible.AccessToken.TokenType]::Impersonation)
|
||||
} finally {
|
||||
$actual_stat.TokenType | Assert-Equal -Expected ([Ansible.AccessToken.TokenType]::Impersonation)
|
||||
}
|
||||
finally {
|
||||
$actual_linked.Dispose()
|
||||
}
|
||||
$actual_linked.IsClosed | Assert-Equals -Expected $true
|
||||
} finally {
|
||||
$actual_linked.IsClosed | Assert-Equal -Expected $true
|
||||
}
|
||||
finally {
|
||||
$h_token.Dispose()
|
||||
}
|
||||
}
|
||||
|
@ -286,29 +306,32 @@ $tests = [Ordered]@{
|
|||
try {
|
||||
$actual_linked = [Ansible.AccessToken.TokenUtil]::GetTokenLinkedToken($h_token)
|
||||
try {
|
||||
$actual_linked.IsClosed | Assert-Equals -Expected $false
|
||||
$actual_linked.IsInvalid | Assert-Equals -Expected $false
|
||||
$actual_linked.IsClosed | Assert-Equal -Expected $false
|
||||
$actual_linked.IsInvalid | Assert-Equal -Expected $false
|
||||
|
||||
$actual_elevation_type = [Ansible.AccessToken.TokenUtil]::GetTokenElevationType($actual_linked)
|
||||
$actual_elevation_type | Assert-Equals -Expected ([Ansible.AccessToken.TokenElevationType]::Full)
|
||||
$actual_elevation_type | Assert-Equal -Expected ([Ansible.AccessToken.TokenElevationType]::Full)
|
||||
|
||||
$actual_stat = [Ansible.AccessToken.TokenUtil]::GetTokenStatistics($actual_linked)
|
||||
$actual_stat.TokenType | Assert-Equals -Expected ([Ansible.AccessToken.TokenType]::Primary)
|
||||
} finally {
|
||||
$actual_stat.TokenType | Assert-Equal -Expected ([Ansible.AccessToken.TokenType]::Primary)
|
||||
}
|
||||
finally {
|
||||
$actual_linked.Dispose()
|
||||
}
|
||||
$actual_linked.IsClosed | Assert-Equals -Expected $true
|
||||
} finally {
|
||||
$actual_linked.IsClosed | Assert-Equal -Expected $true
|
||||
}
|
||||
finally {
|
||||
[Ansible.AccessToken.TokenUtil]::RevertToSelf()
|
||||
}
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
$h_token.Dispose()
|
||||
}
|
||||
|
||||
$tested = $true
|
||||
break
|
||||
}
|
||||
$tested | Assert-Equals -Expected $true
|
||||
$tested | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"Failed to get token information" = {
|
||||
|
@ -318,13 +341,16 @@ $tests = [Ordered]@{
|
|||
$failed = $false
|
||||
try {
|
||||
[Ansible.AccessToken.TokenUtil]::GetTokenUser($h_token)
|
||||
} catch [Ansible.AccessToken.Win32Exception] {
|
||||
}
|
||||
catch [Ansible.AccessToken.Win32Exception] {
|
||||
$failed = $true
|
||||
$_.Exception.Message | Assert-Equals -Expected "GetTokenInformation(TokenUser) failed to get buffer length (Access is denied, Win32ErrorCode 5 - 0x00000005)"
|
||||
} finally {
|
||||
$msg = "GetTokenInformation(TokenUser) failed to get buffer length (Access is denied, Win32ErrorCode 5 - 0x00000005)"
|
||||
$_.Exception.Message | Assert-Equal -Expected $msg
|
||||
}
|
||||
finally {
|
||||
$h_token.Dispose()
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"Logon with valid credentials" = {
|
||||
|
@ -333,39 +359,42 @@ $tests = [Ordered]@{
|
|||
|
||||
$h_token = [Ansible.AccessToken.TokenUtil]::LogonUser($test_username, $null, $test_password, "Network", "Default")
|
||||
try {
|
||||
$h_token.IsClosed | Assert-Equals -Expected $false
|
||||
$h_token.IsInvalid | Assert-Equals -Expected $false
|
||||
$h_token.IsClosed | Assert-Equal -Expected $false
|
||||
$h_token.IsInvalid | Assert-Equal -Expected $false
|
||||
|
||||
$actual_user = [Ansible.AccessToken.TokenUtil]::GetTokenUser($h_token)
|
||||
$actual_user | Assert-Equals -Expected $expected_sid
|
||||
} finally {
|
||||
$actual_user | Assert-Equal -Expected $expected_sid
|
||||
}
|
||||
finally {
|
||||
$h_token.Dispose()
|
||||
}
|
||||
$h_token.IsClosed | Assert-Equals -Expected $true
|
||||
$h_token.IsClosed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"Logon with invalid credentials" = {
|
||||
$failed = $false
|
||||
try {
|
||||
[Ansible.AccessToken.TokenUtil]::LogonUser("fake-user", $null, "fake-pass", "Network", "Default")
|
||||
} catch [Ansible.AccessToken.Win32Exception] {
|
||||
$failed = $true
|
||||
$_.Exception.Message.Contains("Failed to logon fake-user") | Assert-Equals -Expected $true
|
||||
$_.Exception.Message.Contains("Win32ErrorCode 1326 - 0x0000052E)") | Assert-Equals -Expected $true
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
catch [Ansible.AccessToken.Win32Exception] {
|
||||
$failed = $true
|
||||
$_.Exception.Message.Contains("Failed to logon fake-user") | Assert-Equal -Expected $true
|
||||
$_.Exception.Message.Contains("Win32ErrorCode 1326 - 0x0000052E)") | Assert-Equal -Expected $true
|
||||
}
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"Logon with invalid credential with domain account" = {
|
||||
$failed = $false
|
||||
try {
|
||||
[Ansible.AccessToken.TokenUtil]::LogonUser("fake-user", "fake-domain", "fake-pass", "Network", "Default")
|
||||
} catch [Ansible.AccessToken.Win32Exception] {
|
||||
$failed = $true
|
||||
$_.Exception.Message.Contains("Failed to logon fake-domain\fake-user") | Assert-Equals -Expected $true
|
||||
$_.Exception.Message.Contains("Win32ErrorCode 1326 - 0x0000052E)") | Assert-Equals -Expected $true
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
catch [Ansible.AccessToken.Win32Exception] {
|
||||
$failed = $true
|
||||
$_.Exception.Message.Contains("Failed to logon fake-domain\fake-user") | Assert-Equal -Expected $true
|
||||
$_.Exception.Message.Contains("Win32ErrorCode 1326 - 0x0000052E)") | Assert-Equal -Expected $true
|
||||
}
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,37 +5,40 @@
|
|||
|
||||
$module = [Ansible.Basic.AnsibleModule]::Create($args, @{})
|
||||
|
||||
Function Assert-Equals {
|
||||
Function Assert-Equal {
|
||||
param(
|
||||
[Parameter(Mandatory=$true, ValueFromPipeline=$true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory=$true, Position=0)][AllowNull()]$Expected
|
||||
[Parameter(Mandatory = $true, ValueFromPipeline = $true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory = $true, Position = 0)][AllowNull()]$Expected
|
||||
)
|
||||
|
||||
$matched = $false
|
||||
if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array]) {
|
||||
$Actual.Count | Assert-Equals -Expected $Expected.Count
|
||||
for ($i = 0; $i -lt $Actual.Count; $i++) {
|
||||
$actual_value = $Actual[$i]
|
||||
$expected_value = $Expected[$i]
|
||||
Assert-Equals -Actual $actual_value -Expected $expected_value
|
||||
process {
|
||||
$matched = $false
|
||||
if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array]) {
|
||||
$Actual.Count | Assert-Equal -Expected $Expected.Count
|
||||
for ($i = 0; $i -lt $Actual.Count; $i++) {
|
||||
$actual_value = $Actual[$i]
|
||||
$expected_value = $Expected[$i]
|
||||
Assert-Equal -Actual $actual_value -Expected $expected_value
|
||||
}
|
||||
$matched = $true
|
||||
}
|
||||
$matched = $true
|
||||
} else {
|
||||
$matched = $Actual -ceq $Expected
|
||||
}
|
||||
|
||||
if (-not $matched) {
|
||||
if ($Actual -is [PSObject]) {
|
||||
$Actual = $Actual.ToString()
|
||||
else {
|
||||
$matched = $Actual -ceq $Expected
|
||||
}
|
||||
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.test = $test
|
||||
$module.Result.actual = $Actual
|
||||
$module.Result.expected = $Expected
|
||||
$module.Result.line = $call_stack.ScriptLineNumber
|
||||
$module.Result.method = $call_stack.Position.Text
|
||||
$module.FailJson("AssertionError: actual != expected")
|
||||
if (-not $matched) {
|
||||
if ($Actual -is [PSObject]) {
|
||||
$Actual = $Actual.ToString()
|
||||
}
|
||||
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.test = $test
|
||||
$module.Result.actual = $Actual
|
||||
$module.Result.expected = $Expected
|
||||
$module.Result.line = $call_stack.ScriptLineNumber
|
||||
$module.Result.method = $call_stack.Position.Text
|
||||
$module.FailJson("AssertionError: actual != expected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -437,101 +440,101 @@ $tests = @{
|
|||
"Runas standard user" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass,
|
||||
"powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "Interactive"
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "Interactive"
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $standard_user_sid
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $medium_integrity_sid
|
||||
}
|
||||
|
||||
"Runas admin user" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass,
|
||||
"powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "Interactive"
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "Interactive"
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $admin_user_sid
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $high_integrity_sid
|
||||
}
|
||||
|
||||
"Runas SYSTEM" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("SYSTEM", $null,
|
||||
"powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "System"
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected "S-1-5-18"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $system_integrity_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "System"
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected "S-1-5-18"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $system_integrity_sid
|
||||
|
||||
$with_domain = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("NT AUTHORITY\System", $null, "whoami.exe")
|
||||
$with_domain.StandardOut | Assert-Equals -Expected "nt authority\system`r`n"
|
||||
$with_domain.StandardOut | Assert-Equal -Expected "nt authority\system`r`n"
|
||||
}
|
||||
|
||||
"Runas LocalService" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("LocalService", $null,
|
||||
"powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "Service"
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected "S-1-5-19"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $system_integrity_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "Service"
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected "S-1-5-19"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $system_integrity_sid
|
||||
|
||||
$with_domain = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("NT AUTHORITY\LocalService", $null, "whoami.exe")
|
||||
$with_domain.StandardOut | Assert-Equals -Expected "nt authority\local service`r`n"
|
||||
$with_domain.StandardOut | Assert-Equal -Expected "nt authority\local service`r`n"
|
||||
}
|
||||
|
||||
"Runas NetworkService" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("NetworkService", $null,
|
||||
"powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "Service"
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected "S-1-5-20"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $system_integrity_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "Service"
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected "S-1-5-20"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $system_integrity_sid
|
||||
|
||||
$with_domain = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("NT AUTHORITY\NetworkService", $null, "whoami.exe")
|
||||
$with_domain.StandardOut | Assert-Equals -Expected "nt authority\network service`r`n"
|
||||
$with_domain.StandardOut | Assert-Equal -Expected "nt authority\network service`r`n"
|
||||
}
|
||||
|
||||
"Runas without working dir set" = {
|
||||
$expected = "$env:SystemRoot\system32`r`n"
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, 0, "Interactive", $null,
|
||||
'powershell.exe $pwd.Path', $null, $null, "")
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"Runas with working dir set" = {
|
||||
$expected = "$env:SystemRoot`r`n"
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, 0, "Interactive", $null,
|
||||
'powershell.exe $pwd.Path', $env:SystemRoot, $null, "")
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"Runas without environment set" = {
|
||||
$expected = "Windows_NT`r`n"
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, 0, "Interactive", $null,
|
||||
'powershell.exe $env:TEST; $env:OS', $null, $null, "")
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"Runas with environment set" = {
|
||||
|
@ -541,52 +544,53 @@ $tests = @{
|
|||
}
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, 0, "Interactive", $null,
|
||||
'cmd.exe /c set', $null, $env_vars, "")
|
||||
("TEST=tesTing" -cin $actual.StandardOut.Split("`r`n")) | Assert-Equals -Expected $true
|
||||
("TEST2=Testing 2" -cin $actual.StandardOut.Split("`r`n")) | Assert-Equals -Expected $true
|
||||
("OS=Windows_NT" -cnotin $actual.StandardOut.Split("`r`n")) | Assert-Equals -Expected $true
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
("TEST=tesTing" -cin $actual.StandardOut.Split("`r`n")) | Assert-Equal -Expected $true
|
||||
("TEST2=Testing 2" -cin $actual.StandardOut.Split("`r`n")) | Assert-Equal -Expected $true
|
||||
("OS=Windows_NT" -cnotin $actual.StandardOut.Split("`r`n")) | Assert-Equal -Expected $true
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"Runas with string stdin" = {
|
||||
$expected = "input value`r`n`r`n"
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, 0, "Interactive", $null,
|
||||
'powershell.exe [System.Console]::In.ReadToEnd()', $null, $null, "input value")
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"Runas with string stdin and newline" = {
|
||||
$expected = "input value`r`n`r`n"
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, 0, "Interactive", $null,
|
||||
'powershell.exe [System.Console]::In.ReadToEnd()', $null, $null, "input value`r`n")
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"Runas with byte stdin" = {
|
||||
$expected = "input value`r`n"
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, 0, "Interactive", $null,
|
||||
'powershell.exe [System.Console]::In.ReadToEnd()', $null, $null, [System.Text.Encoding]::UTF8.GetBytes("input value"))
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"Missing executable" = {
|
||||
$failed = $false
|
||||
try {
|
||||
[Ansible.Become.BecomeUtil]::CreateProcessAsUser("SYSTEM", $null, "fake.exe")
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
$failed = $true
|
||||
$_.Exception.InnerException.GetType().FullName | Assert-Equals -Expected "Ansible.Process.Win32Exception"
|
||||
$_.Exception.InnerException.GetType().FullName | Assert-Equal -Expected "Ansible.Process.Win32Exception"
|
||||
$expected = 'Exception calling "CreateProcessAsUser" with "3" argument(s): "CreateProcessWithTokenW() failed '
|
||||
$expected += '(The system cannot find the file specified, Win32ErrorCode 2)"'
|
||||
$_.Exception.Message | Assert-Equals -Expected $expected
|
||||
$_.Exception.Message | Assert-Equal -Expected $expected
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"CreateProcessAsUser with lpApplicationName" = {
|
||||
|
@ -594,112 +598,114 @@ $tests = @{
|
|||
$full_path = "$($env:SystemRoot)\System32\WindowsPowerShell\v1.0\powershell.exe"
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("SYSTEM", $null, 0, "Interactive", $full_path,
|
||||
"Write-Output 'abc'", $null, $null, "")
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("SYSTEM", $null, 0, "Interactive", $full_path,
|
||||
"powershell.exe Write-Output 'abc'", $null, $null, "")
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcessAsUser with stderr" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("SYSTEM", $null, 0, "Interactive", $null,
|
||||
"powershell.exe [System.Console]::Error.WriteLine('hi')", $null, $null, "")
|
||||
$actual.StandardOut | Assert-Equals -Expected ""
|
||||
$actual.StandardError | Assert-Equals -Expected "hi`r`n"
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected ""
|
||||
$actual.StandardError | Assert-Equal -Expected "hi`r`n"
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcessAsUser with exit code" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("SYSTEM", $null, 0, "Interactive", $null,
|
||||
"powershell.exe exit 10", $null, $null, "")
|
||||
$actual.StandardOut | Assert-Equals -Expected ""
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 10
|
||||
$actual.StandardOut | Assert-Equal -Expected ""
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 10
|
||||
}
|
||||
|
||||
"Local account with computer name" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("$env:COMPUTERNAME\$standard_user", $become_pass,
|
||||
"powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "Interactive"
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "Interactive"
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $standard_user_sid
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $medium_integrity_sid
|
||||
}
|
||||
|
||||
"Local account with computer as period" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser(".\$standard_user", $become_pass,
|
||||
"powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "Interactive"
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "Interactive"
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $standard_user_sid
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $medium_integrity_sid
|
||||
}
|
||||
|
||||
"Local account with invalid password" = {
|
||||
$failed = $false
|
||||
try {
|
||||
[Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, "incorrect", "powershell.exe Write-Output abc")
|
||||
} catch {
|
||||
$failed = $true
|
||||
$_.Exception.InnerException.GetType().FullName | Assert-Equals -Expected "Ansible.AccessToken.Win32Exception"
|
||||
# Server 2008 has a slightly different error msg, just assert we get the error 1326
|
||||
($_.Exception.Message.Contains("Win32ErrorCode 1326")) | Assert-Equals -Expected $true
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
catch {
|
||||
$failed = $true
|
||||
$_.Exception.InnerException.GetType().FullName | Assert-Equal -Expected "Ansible.AccessToken.Win32Exception"
|
||||
# Server 2008 has a slightly different error msg, just assert we get the error 1326
|
||||
($_.Exception.Message.Contains("Win32ErrorCode 1326")) | Assert-Equal -Expected $true
|
||||
}
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"Invalid account" = {
|
||||
$failed = $false
|
||||
try {
|
||||
[Ansible.Become.BecomeUtil]::CreateProcessAsUser("incorrect", "incorrect", "powershell.exe Write-Output abc")
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
$failed = $true
|
||||
$_.Exception.InnerException.GetType().FullName | Assert-Equals -Expected "System.Security.Principal.IdentityNotMappedException"
|
||||
$_.Exception.InnerException.GetType().FullName | Assert-Equal -Expected "System.Security.Principal.IdentityNotMappedException"
|
||||
$expected = 'Exception calling "CreateProcessAsUser" with "3" argument(s): "Some or all '
|
||||
$expected += 'identity references could not be translated."'
|
||||
$_.Exception.Message | Assert-Equals -Expected $expected
|
||||
$_.Exception.Message | Assert-Equal -Expected $expected
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"Interactive logon with standard" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, "WithProfile",
|
||||
"Interactive", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "Interactive"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.SourceName | Assert-Equals -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "Interactive"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $medium_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.SourceName | Assert-Equal -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $standard_user_sid
|
||||
}
|
||||
|
||||
"Batch logon with standard" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, "WithProfile",
|
||||
"Batch", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "Batch"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.SourceName | Assert-Equals -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "Batch"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $medium_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.SourceName | Assert-Equal -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $standard_user_sid
|
||||
}
|
||||
|
||||
"Network logon with standard" = {
|
||||
|
@ -709,15 +715,15 @@ $tests = @{
|
|||
}
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, "WithProfile",
|
||||
"Network", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "Network"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.SourceName | Assert-Equals -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "Network"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $medium_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.SourceName | Assert-Equal -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $standard_user_sid
|
||||
}
|
||||
|
||||
"Network with cleartext logon with standard" = {
|
||||
|
@ -727,31 +733,31 @@ $tests = @{
|
|||
}
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, "WithProfile",
|
||||
"NetworkCleartext", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "NetworkCleartext"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.SourceName | Assert-Equals -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "NetworkCleartext"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $medium_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.SourceName | Assert-Equal -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $standard_user_sid
|
||||
}
|
||||
|
||||
"Logon without password with standard" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, [NullString]::Value, "WithProfile",
|
||||
"Interactive", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
# Too unstable, there might be another process still lingering which causes become to steal instead of using
|
||||
# S4U. Just don't check the type and source to verify we can become without a password
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
# $stdout.LogonType | Assert-Equals -Expected "Batch"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
# $stdout.SourceName | Assert-Equals -Expected "ansible"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
|
||||
# $stdout.LogonType | Assert-Equal -Expected "Batch"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $medium_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
# $stdout.SourceName | Assert-Equal -Expected "ansible"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $standard_user_sid
|
||||
}
|
||||
|
||||
"Logon without password and network type with standard" = {
|
||||
|
@ -761,45 +767,45 @@ $tests = @{
|
|||
}
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, [NullString]::Value, "WithProfile",
|
||||
"Network", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
# Too unstable, there might be another process still lingering which causes become to steal instead of using
|
||||
# S4U. Just don't check the type and source to verify we can become without a password
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
# $stdout.LogonType | Assert-Equals -Expected "Network"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
# $stdout.SourceName | Assert-Equals -Expected "ansible"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
|
||||
# $stdout.LogonType | Assert-Equal -Expected "Network"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $medium_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
# $stdout.SourceName | Assert-Equal -Expected "ansible"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $standard_user_sid
|
||||
}
|
||||
|
||||
"Interactive logon with admin" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, "WithProfile",
|
||||
"Interactive", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "Interactive"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.SourceName | Assert-Equals -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "Interactive"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.SourceName | Assert-Equal -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $admin_user_sid
|
||||
}
|
||||
|
||||
"Batch logon with admin" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, "WithProfile",
|
||||
"Batch", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "Batch"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.SourceName | Assert-Equals -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "Batch"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.SourceName | Assert-Equal -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $admin_user_sid
|
||||
}
|
||||
|
||||
"Network logon with admin" = {
|
||||
|
@ -809,15 +815,15 @@ $tests = @{
|
|||
}
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, "WithProfile",
|
||||
"Network", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "Network"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.SourceName | Assert-Equals -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "Network"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.SourceName | Assert-Equal -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $admin_user_sid
|
||||
}
|
||||
|
||||
"Network with cleartext logon with admin" = {
|
||||
|
@ -827,15 +833,15 @@ $tests = @{
|
|||
}
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, "WithProfile",
|
||||
"NetworkCleartext", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "NetworkCleartext"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
$stdout.SourceName | Assert-Equals -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "NetworkCleartext"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
$stdout.SourceName | Assert-Equal -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $admin_user_sid
|
||||
}
|
||||
|
||||
"Fail to logon with null or empty password" = {
|
||||
|
@ -846,30 +852,31 @@ $tests = @{
|
|||
# use [NullString]::Value instead if we want that behaviour. This just tests to see that an empty
|
||||
# string won't go the S4U route.
|
||||
[Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $null, "WithProfile",
|
||||
"Interactive", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
} catch {
|
||||
$failed = $true
|
||||
$_.Exception.InnerException.GetType().FullName | Assert-Equals -Expected "Ansible.AccessToken.Win32Exception"
|
||||
# Server 2008 has a slightly different error msg, just assert we get the error 1326
|
||||
($_.Exception.Message.Contains("Win32ErrorCode 1326")) | Assert-Equals -Expected $true
|
||||
"Interactive", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
catch {
|
||||
$failed = $true
|
||||
$_.Exception.InnerException.GetType().FullName | Assert-Equal -Expected "Ansible.AccessToken.Win32Exception"
|
||||
# Server 2008 has a slightly different error msg, just assert we get the error 1326
|
||||
($_.Exception.Message.Contains("Win32ErrorCode 1326")) | Assert-Equal -Expected $true
|
||||
}
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"Logon without password with admin" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, [NullString]::Value, "WithProfile",
|
||||
"Interactive", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
# Too unstable, there might be another process still lingering which causes become to steal instead of using
|
||||
# S4U. Just don't check the type and source to verify we can become without a password
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
# $stdout.LogonType | Assert-Equals -Expected "Batch"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
# $stdout.SourceName | Assert-Equals -Expected "ansible"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
|
||||
# $stdout.LogonType | Assert-Equal -Expected "Batch"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
# $stdout.SourceName | Assert-Equal -Expected "ansible"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $admin_user_sid
|
||||
}
|
||||
|
||||
"Logon without password and network type with admin" = {
|
||||
|
@ -879,17 +886,17 @@ $tests = @{
|
|||
}
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, [NullString]::Value, "WithProfile",
|
||||
"Network", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
# Too unstable, there might be another process still lingering which causes become to steal instead of using
|
||||
# S4U. Just don't check the type and source to verify we can become without a password
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
# $stdout.LogonType | Assert-Equals -Expected "Network"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $true
|
||||
# $stdout.SourceName | Assert-Equals -Expected "ansible"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
|
||||
# $stdout.LogonType | Assert-Equal -Expected "Network"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $true
|
||||
# $stdout.SourceName | Assert-Equal -Expected "ansible"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $admin_user_sid
|
||||
}
|
||||
|
||||
"Logon without profile with admin" = {
|
||||
|
@ -900,45 +907,45 @@ $tests = @{
|
|||
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, 0,
|
||||
"Interactive", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "Interactive"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $false
|
||||
$stdout.SourceName | Assert-Equals -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
|
||||
$stdout.LogonType | Assert-Equal -Expected "Interactive"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $high_integrity_sid
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $false
|
||||
$stdout.SourceName | Assert-Equal -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $admin_user_sid
|
||||
}
|
||||
|
||||
"Logon with network credentials and no profile" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("fakeuser", "fakepassword", "NetcredentialsOnly",
|
||||
"NewCredentials", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "NewCredentials"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $current_user.MandatoryLabelSid.Value
|
||||
$stdout.LogonType | Assert-Equal -Expected "NewCredentials"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $current_user.MandatoryLabelSid.Value
|
||||
|
||||
# while we didn't set WithProfile, the new process is based on the current process
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $current_user.ProfileLoaded
|
||||
$stdout.SourceName | Assert-Equals -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $current_user.UserSid.Value
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $current_user.ProfileLoaded
|
||||
$stdout.SourceName | Assert-Equal -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $current_user.UserSid.Value
|
||||
}
|
||||
|
||||
"Logon with network credentials and with profile" = {
|
||||
$actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("fakeuser", "fakepassword", "NetcredentialsOnly, WithProfile",
|
||||
"NewCredentials", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$stdout = ConvertFrom-Json -InputObject $actual.StandardOut
|
||||
$stdout.LogonType | Assert-Equals -Expected "NewCredentials"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $current_user.MandatoryLabelSid.Value
|
||||
$stdout.ProfileLoaded | Assert-Equals -Expected $current_user.ProfileLoaded
|
||||
$stdout.SourceName | Assert-Equals -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equals -Expected $current_user.UserSid.Value
|
||||
$stdout.LogonType | Assert-Equal -Expected "NewCredentials"
|
||||
$stdout.MandatoryLabelSid.Value | Assert-Equal -Expected $current_user.MandatoryLabelSid.Value
|
||||
$stdout.ProfileLoaded | Assert-Equal -Expected $current_user.ProfileLoaded
|
||||
$stdout.SourceName | Assert-Equal -Expected "Advapi"
|
||||
$stdout.UserSid.Value | Assert-Equal -Expected $current_user.UserSid.Value
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -965,7 +972,8 @@ try {
|
|||
$user_obj = $adsi.Create("User", $user)
|
||||
$user_obj.SetPassword($become_pass)
|
||||
$user_obj.SetInfo()
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$user_obj.SetPassword($become_pass)
|
||||
}
|
||||
$user_obj.RefreshCache()
|
||||
|
@ -973,13 +981,17 @@ try {
|
|||
if ($user -eq $standard_user) {
|
||||
$standard_user_sid = (New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList @($user_obj.ObjectSid.Value, 0)).Value
|
||||
$group = [System.Security.Principal.WellKnownSidType]::BuiltinUsersSid
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$admin_user_sid = (New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList @($user_obj.ObjectSid.Value, 0)).Value
|
||||
$group = [System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid
|
||||
}
|
||||
$group = (New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList $group, $null).Value
|
||||
[string[]]$current_groups = $user_obj.Groups() | ForEach-Object {
|
||||
New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList @($_.GetType().InvokeMember("objectSID", "GetProperty", $null, $_, $null), 0)
|
||||
New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList @(
|
||||
$_.GetType().InvokeMember("objectSID", "GetProperty", $null, $_, $null),
|
||||
0
|
||||
)
|
||||
}
|
||||
if ($current_groups -notcontains $group) {
|
||||
$group_obj = $adsi.Children | Where-Object {
|
||||
|
@ -995,7 +1007,8 @@ try {
|
|||
$test = $test_impl.Key
|
||||
&$test_impl.Value
|
||||
}
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
Remove-Item -LiteralPath $tmp_dir -Force -Recurse
|
||||
foreach ($user in $standard_user, $admin_user) {
|
||||
$user_obj = $adsi.Children | Where-Object { $_.SchemaClassName -eq "User" -and $_.Name -eq $user }
|
||||
|
|
|
@ -9,10 +9,13 @@ $result = @{
|
|||
changed = $false
|
||||
}
|
||||
|
||||
Function Assert-Equals($actual, $expected) {
|
||||
Function Assert-Equal($actual, $expected) {
|
||||
if ($actual -cne $expected) {
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$error_msg = "AssertionError:`r`nActual: `"$actual`" != Expected: `"$expected`"`r`nLine: $($call_stack.ScriptLineNumber), Method: $($call_stack.Position.Text)"
|
||||
$error_msg = -join @(
|
||||
"AssertionError:`r`nActual: `"$actual`" != Expected: `"$expected`"`r`nLine: "
|
||||
"$($call_stack.ScriptLineNumber), Method: $($call_stack.Position.Text)"
|
||||
)
|
||||
Fail-Json -obj $result -message $error_msg
|
||||
}
|
||||
}
|
||||
|
@ -34,15 +37,16 @@ namespace Namespace1
|
|||
}
|
||||
'@
|
||||
$res = Add-CSharpType -References $code
|
||||
Assert-Equals -actual $res -expected $null
|
||||
Assert-Equal -actual $res -expected $null
|
||||
|
||||
$actual = [Namespace1.Class1]::GetString($false)
|
||||
Assert-Equals $actual -expected "Hello World"
|
||||
Assert-Equal $actual -expected "Hello World"
|
||||
|
||||
try {
|
||||
[Namespace1.Class1]::GetString($true)
|
||||
} catch {
|
||||
Assert-Equals ($_.Exception.ToString().Contains("at Namespace1.Class1.GetString(Boolean error)`r`n")) -expected $true
|
||||
}
|
||||
catch {
|
||||
Assert-Equal ($_.Exception.ToString().Contains("at Namespace1.Class1.GetString(Boolean error)`r`n")) -expected $true
|
||||
}
|
||||
|
||||
$code_debug = @'
|
||||
|
@ -62,17 +66,18 @@ namespace Namespace2
|
|||
}
|
||||
'@
|
||||
$res = Add-CSharpType -References $code_debug -IncludeDebugInfo
|
||||
Assert-Equals -actual $res -expected $null
|
||||
Assert-Equal -actual $res -expected $null
|
||||
|
||||
$actual = [Namespace2.Class2]::GetString($false)
|
||||
Assert-Equals $actual -expected "Hello World"
|
||||
Assert-Equal $actual -expected "Hello World"
|
||||
|
||||
try {
|
||||
[Namespace2.Class2]::GetString($true)
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
$tmp_path = [System.IO.Path]::GetFullPath($env:TMP).ToLower()
|
||||
Assert-Equals ($_.Exception.ToString().ToLower().Contains("at namespace2.class2.getstring(boolean error) in $tmp_path")) -expected $true
|
||||
Assert-Equals ($_.Exception.ToString().Contains(".cs:line 10")) -expected $true
|
||||
Assert-Equal ($_.Exception.ToString().ToLower().Contains("at namespace2.class2.getstring(boolean error) in $tmp_path")) -expected $true
|
||||
Assert-Equal ($_.Exception.ToString().Contains(".cs:line 10")) -expected $true
|
||||
}
|
||||
|
||||
$code_tmp = @'
|
||||
|
@ -93,19 +98,21 @@ namespace Namespace3
|
|||
'@
|
||||
$tmp_path = $env:USERPROFILE
|
||||
$res = Add-CSharpType -References $code_tmp -IncludeDebugInfo -TempPath $tmp_path -PassThru
|
||||
Assert-Equals -actual $res.GetType().Name -expected "RuntimeAssembly"
|
||||
Assert-Equals -actual $res.Location -expected ""
|
||||
Assert-Equals -actual $res.GetTypes().Length -expected 1
|
||||
Assert-Equals -actual $res.GetTypes()[0].Name -expected "Class3"
|
||||
Assert-Equal -actual $res.GetType().Name -expected "RuntimeAssembly"
|
||||
Assert-Equal -actual $res.Location -expected ""
|
||||
Assert-Equal -actual $res.GetTypes().Length -expected 1
|
||||
Assert-Equal -actual $res.GetTypes()[0].Name -expected "Class3"
|
||||
|
||||
$actual = [Namespace3.Class3]::GetString($false)
|
||||
Assert-Equals $actual -expected "Hello World"
|
||||
Assert-Equal $actual -expected "Hello World"
|
||||
|
||||
try {
|
||||
[Namespace3.Class3]::GetString($true)
|
||||
} catch {
|
||||
Assert-Equals ($_.Exception.ToString().ToLower().Contains("at namespace3.class3.getstring(boolean error) in $($tmp_path.ToLower())")) -expected $true
|
||||
Assert-Equals ($_.Exception.ToString().Contains(".cs:line 10")) -expected $true
|
||||
}
|
||||
catch {
|
||||
$actual = $_.Exception.ToString().ToLower().Contains("at namespace3.class3.getstring(boolean error) in $($tmp_path.ToLower())")
|
||||
Assert-Equal $actual -expected $true
|
||||
Assert-Equal ($_.Exception.ToString().Contains(".cs:line 10")) -expected $true
|
||||
}
|
||||
|
||||
$warning_code = @'
|
||||
|
@ -130,15 +137,17 @@ namespace Namespace4
|
|||
$failed = $false
|
||||
try {
|
||||
Add-CSharpType -References $warning_code
|
||||
} catch {
|
||||
$failed = $true
|
||||
Assert-Equals -actual ($_.Exception.Message.Contains("error CS0219: Warning as Error: The variable 'a' is assigned but its value is never used")) -expected $true
|
||||
}
|
||||
Assert-Equals -actual $failed -expected $true
|
||||
catch {
|
||||
$failed = $true
|
||||
$actual = $_.Exception.Message.Contains("error CS0219: Warning as Error: The variable 'a' is assigned but its value is never used")
|
||||
Assert-Equal -actual $actual -expected $true
|
||||
}
|
||||
Assert-Equal -actual $failed -expected $true
|
||||
|
||||
Add-CSharpType -References $warning_code -IgnoreWarnings
|
||||
$actual = [Namespace4.Class4]::GetString($true)
|
||||
Assert-Equals -actual $actual -expected "Hello World"
|
||||
Assert-Equal -actual $actual -expected "Hello World"
|
||||
|
||||
$reference_1 = @'
|
||||
using System;
|
||||
|
@ -181,7 +190,7 @@ namespace Namespace6
|
|||
|
||||
Add-CSharpType -References $reference_1, $reference_2
|
||||
$actual = [Namespace6.Class6]::GetString()
|
||||
Assert-Equals -actual $actual -expected "Hello World"
|
||||
Assert-Equal -actual $actual -expected "Hello World"
|
||||
|
||||
$ignored_warning = @'
|
||||
using System;
|
||||
|
@ -202,7 +211,7 @@ namespace Namespace7
|
|||
'@
|
||||
Add-CSharpType -References $ignored_warning
|
||||
$actual = [Namespace7.Class7]::GetString()
|
||||
Assert-Equals -actual $actual -expected "abc"
|
||||
Assert-Equal -actual $actual -expected "abc"
|
||||
|
||||
$defined_symbol = @'
|
||||
using System;
|
||||
|
@ -225,7 +234,7 @@ namespace Namespace8
|
|||
'@
|
||||
Add-CSharpType -References $defined_symbol -CompileSymbols "SYMBOL1"
|
||||
$actual = [Namespace8.Class8]::GetString()
|
||||
Assert-Equals -actual $actual -expected "symbol"
|
||||
Assert-Equal -actual $actual -expected "symbol"
|
||||
|
||||
$type_accelerator = @'
|
||||
using System;
|
||||
|
@ -245,7 +254,7 @@ namespace Namespace9
|
|||
'@
|
||||
Add-CSharpType -Reference $type_accelerator
|
||||
$actual = [AnsibleType]::GetString()
|
||||
Assert-Equals -actual $actual -expected "a"
|
||||
Assert-Equal -actual $actual -expected "a"
|
||||
|
||||
$missing_type_class = @'
|
||||
using System;
|
||||
|
@ -266,11 +275,12 @@ namespace Namespace10
|
|||
$failed = $false
|
||||
try {
|
||||
Add-CSharpType -Reference $missing_type_class
|
||||
} catch {
|
||||
$failed = $true
|
||||
Assert-Equals -actual $_.Exception.Message -expected "Failed to find compiled class 'MissingClass' for custom TypeAccelerator."
|
||||
}
|
||||
Assert-Equals -actual $failed -expected $true
|
||||
catch {
|
||||
$failed = $true
|
||||
Assert-Equal -actual $_.Exception.Message -expected "Failed to find compiled class 'MissingClass' for custom TypeAccelerator."
|
||||
}
|
||||
Assert-Equal -actual $failed -expected $true
|
||||
|
||||
$arch_class = @'
|
||||
using System;
|
||||
|
@ -293,7 +303,7 @@ namespace Namespace11
|
|||
}
|
||||
'@
|
||||
Add-CSharpType -Reference $arch_class
|
||||
Assert-Equals -actual ([Namespace11.Class11]::GetIntPtrSize()) -expected ([System.IntPtr]::Size)
|
||||
Assert-Equal -actual ([Namespace11.Class11]::GetIntPtrSize()) -expected ([System.IntPtr]::Size)
|
||||
|
||||
$lib_set = @'
|
||||
using System;
|
||||
|
@ -316,7 +326,7 @@ try {
|
|||
finally {
|
||||
Remove-Item -LiteralPath env:\LIB
|
||||
}
|
||||
Assert-Equals -actual ([Namespace12.Class12]::GetString()) -expected "b"
|
||||
Assert-Equal -actual ([Namespace12.Class12]::GetString()) -expected "b"
|
||||
|
||||
$result.res = "success"
|
||||
Exit-Json -obj $result
|
||||
|
|
|
@ -8,37 +8,40 @@
|
|||
|
||||
$module = [Ansible.Basic.AnsibleModule]::Create($args, @{})
|
||||
|
||||
Function Assert-Equals {
|
||||
Function Assert-Equal {
|
||||
param(
|
||||
[Parameter(Mandatory=$true, ValueFromPipeline=$true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory=$true, Position=0)][AllowNull()]$Expected
|
||||
[Parameter(Mandatory = $true, ValueFromPipeline = $true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory = $true, Position = 0)][AllowNull()]$Expected
|
||||
)
|
||||
|
||||
$matched = $false
|
||||
if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array]) {
|
||||
$Actual.Count | Assert-Equals -Expected $Expected.Count
|
||||
for ($i = 0; $i -lt $Actual.Count; $i++) {
|
||||
$actual_value = $Actual[$i]
|
||||
$expected_value = $Expected[$i]
|
||||
Assert-Equals -Actual $actual_value -Expected $expected_value
|
||||
process {
|
||||
$matched = $false
|
||||
if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array]) {
|
||||
$Actual.Count | Assert-Equal -Expected $Expected.Count
|
||||
for ($i = 0; $i -lt $Actual.Count; $i++) {
|
||||
$actual_value = $Actual[$i]
|
||||
$expected_value = $Expected[$i]
|
||||
Assert-Equal -Actual $actual_value -Expected $expected_value
|
||||
}
|
||||
$matched = $true
|
||||
}
|
||||
$matched = $true
|
||||
} else {
|
||||
$matched = $Actual -ceq $Expected
|
||||
}
|
||||
|
||||
if (-not $matched) {
|
||||
if ($Actual -is [PSObject]) {
|
||||
$Actual = $Actual.ToString()
|
||||
else {
|
||||
$matched = $Actual -ceq $Expected
|
||||
}
|
||||
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.test = $test
|
||||
$module.Result.actual = $Actual
|
||||
$module.Result.expected = $Expected
|
||||
$module.Result.line = $call_stack.ScriptLineNumber
|
||||
$module.Result.method = $call_stack.Position.Text
|
||||
$module.FailJson("AssertionError: actual != expected")
|
||||
if (-not $matched) {
|
||||
if ($Actual -is [PSObject]) {
|
||||
$Actual = $Actual.ToString()
|
||||
}
|
||||
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.test = $test
|
||||
$module.Result.actual = $Actual
|
||||
$module.Result.expected = $Expected
|
||||
$module.Result.line = $call_stack.ScriptLineNumber
|
||||
$module.Result.method = $call_stack.Position.Text
|
||||
$module.FailJson("AssertionError: actual != expected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +50,7 @@ $tmp_dir = $module.Tmpdir
|
|||
$tests = @{
|
||||
"Test backup file with missing file" = {
|
||||
$actual = Backup-File -path (Join-Path -Path $tmp_dir -ChildPath "missing")
|
||||
$actual | Assert-Equals -Expected $null
|
||||
$actual | Assert-Equal -Expected $null
|
||||
}
|
||||
|
||||
"Test backup file in check mode" = {
|
||||
|
@ -55,12 +58,12 @@ $tests = @{
|
|||
Set-Content -LiteralPath $orig_file -Value "abc"
|
||||
$actual = Backup-File -path $orig_file -WhatIf
|
||||
|
||||
(Test-Path -LiteralPath $actual) | Assert-Equals -Expected $false
|
||||
(Test-Path -LiteralPath $actual) | Assert-Equal -Expected $false
|
||||
|
||||
$parent_dir = Split-Path -LiteralPath $actual
|
||||
$backup_file = Split-Path -Path $actual -Leaf
|
||||
$parent_dir | Assert-Equals -Expected $tmp_dir
|
||||
($backup_file -match "^file-check\.txt\.$pid\.\d{8}-\d{6}\.bak$") | Assert-Equals -Expected $true
|
||||
$parent_dir | Assert-Equal -Expected $tmp_dir
|
||||
($backup_file -match "^file-check\.txt\.$pid\.\d{8}-\d{6}\.bak$") | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"Test backup file" = {
|
||||
|
@ -69,13 +72,13 @@ $tests = @{
|
|||
Set-Content -LiteralPath $orig_file -Value $content
|
||||
$actual = Backup-File -path $orig_file
|
||||
|
||||
(Test-Path -LiteralPath $actual) | Assert-Equals -Expected $true
|
||||
(Test-Path -LiteralPath $actual) | Assert-Equal -Expected $true
|
||||
|
||||
$parent_dir = Split-Path -LiteralPath $actual
|
||||
$backup_file = Split-Path -Path $actual -Leaf
|
||||
$parent_dir | Assert-Equals -Expected $tmp_dir
|
||||
($backup_file -match "^file\.txt\.$pid\.\d{8}-\d{6}\.bak$") | Assert-Equals -Expected $true
|
||||
(Get-Content -LiteralPath $actual -Raw) | Assert-Equals -Expected "$content`r`n"
|
||||
$parent_dir | Assert-Equal -Expected $tmp_dir
|
||||
($backup_file -match "^file\.txt\.$pid\.\d{8}-\d{6}\.bak$") | Assert-Equal -Expected $true
|
||||
(Get-Content -LiteralPath $actual -Raw) | Assert-Equal -Expected "$content`r`n"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
Function Assert-Equals($actual, $expected) {
|
||||
Function Assert-Equal($actual, $expected) {
|
||||
if ($actual -cne $expected) {
|
||||
Fail-Json @{} "actual != expected`nActual: $actual`nExpected: $expected"
|
||||
}
|
||||
|
@ -41,33 +41,40 @@ foreach ($entry in $output_dict.GetEnumerator()) {
|
|||
$value = $entry.Value
|
||||
|
||||
if ($value -is [Hashtable]) {
|
||||
Assert-Equals -actual $key -expected "inner_hash_table"
|
||||
Assert-Equal -actual $key -expected "inner_hash_table"
|
||||
foreach ($inner_hash in $value.GetEnumerator()) {
|
||||
Assert-Equals -actual $inner_hash.Name -expected $inner_hash.Value
|
||||
Assert-Equal -actual $inner_hash.Name -expected $inner_hash.Value
|
||||
}
|
||||
} elseif ($value -is [Array] -or $value -is [System.Collections.ArrayList]) {
|
||||
}
|
||||
elseif ($value -is [Array] -or $value -is [System.Collections.ArrayList]) {
|
||||
if ($key -eq "list_dict") {
|
||||
foreach ($inner_list in $value) {
|
||||
if ($inner_list -is [Hashtable]) {
|
||||
foreach ($inner_list_hash in $inner_list.GetEnumerator()) {
|
||||
Assert-Equals -actual $inner_list_hash.Name -expected $inner_list_hash.Value
|
||||
Assert-Equal -actual $inner_list_hash.Name -expected $inner_list_hash.Value
|
||||
}
|
||||
} elseif ($inner_list -is [String]) {
|
||||
}
|
||||
elseif ($inner_list -is [String]) {
|
||||
# this is not a string key so we need to keep it the same
|
||||
Assert-Equals -actual $inner_list -expected "stringTwo"
|
||||
} else {
|
||||
Assert-Equals -actual $inner_list -expected 0
|
||||
Assert-Equal -actual $inner_list -expected "stringTwo"
|
||||
}
|
||||
else {
|
||||
Assert-Equal -actual $inner_list -expected 0
|
||||
}
|
||||
}
|
||||
} elseif ($key -eq "empty_list") {
|
||||
Assert-Equals -actual $value.Count -expected 0
|
||||
} elseif ($key -eq "single_list") {
|
||||
Assert-Equals -actual $value.Count -expected 1
|
||||
} else {
|
||||
}
|
||||
elseif ($key -eq "empty_list") {
|
||||
Assert-Equal -actual $value.Count -expected 0
|
||||
}
|
||||
elseif ($key -eq "single_list") {
|
||||
Assert-Equal -actual $value.Count -expected 1
|
||||
}
|
||||
else {
|
||||
Fail-Json -obj $result -message "invalid key found for list $key"
|
||||
}
|
||||
} else {
|
||||
Assert-Equals -actual $key -expected $value
|
||||
}
|
||||
else {
|
||||
Assert-Equal -actual $key -expected $value
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ $exe_directory = Split-Path -Path $exe -Parent
|
|||
$exe_filename = Split-Path -Path $exe -Leaf
|
||||
$test_name = $null
|
||||
|
||||
Function Assert-Equals($actual, $expected) {
|
||||
Function Assert-Equal($actual, $expected) {
|
||||
if ($actual -cne $expected) {
|
||||
Fail-Json -obj $result -message "Test $test_name failed`nActual: '$actual' != Expected: '$expected'"
|
||||
}
|
||||
|
@ -24,10 +24,10 @@ Function Assert-Equals($actual, $expected) {
|
|||
|
||||
$test_name = "full exe path"
|
||||
$actual = Run-Command -command "`"$exe`" arg1 arg2 `"arg 3`""
|
||||
Assert-Equals -actual $actual.rc -expected 0
|
||||
Assert-Equals -actual $actual.stdout -expected "arg1`r`narg2`r`narg 3`r`n"
|
||||
Assert-Equals -actual $actual.stderr -expected ""
|
||||
Assert-Equals -actual $actual.executable -expected $exe
|
||||
Assert-Equal -actual $actual.rc -expected 0
|
||||
Assert-Equal -actual $actual.stdout -expected "arg1`r`narg2`r`narg 3`r`n"
|
||||
Assert-Equal -actual $actual.stderr -expected ""
|
||||
Assert-Equal -actual $actual.executable -expected $exe
|
||||
|
||||
$test_name = "exe in special char dir"
|
||||
$tmp_dir = Join-Path -Path $env:TEMP -ChildPath "ansible .ÅÑŚÌβŁÈ [$!@^&test(;)]"
|
||||
|
@ -36,66 +36,70 @@ try {
|
|||
$exe_special = Join-Path $tmp_dir -ChildPath "PrintArgv.exe"
|
||||
Copy-Item -LiteralPath $exe -Destination $exe_special
|
||||
$actual = Run-Command -command "`"$exe_special`" arg1 arg2 `"arg 3`""
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
Remove-Item -LiteralPath $tmp_dir -Force -Recurse
|
||||
}
|
||||
Assert-Equals -actual $actual.rc -expected 0
|
||||
Assert-Equals -actual $actual.stdout -expected "arg1`r`narg2`r`narg 3`r`n"
|
||||
Assert-Equals -actual $actual.stderr -expected ""
|
||||
Assert-Equals -actual $actual.executable -expected $exe_special
|
||||
Assert-Equal -actual $actual.rc -expected 0
|
||||
Assert-Equal -actual $actual.stdout -expected "arg1`r`narg2`r`narg 3`r`n"
|
||||
Assert-Equal -actual $actual.stderr -expected ""
|
||||
Assert-Equal -actual $actual.executable -expected $exe_special
|
||||
|
||||
$test_name = "invalid exe path"
|
||||
try {
|
||||
$actual = Run-Command -command "C:\fakepath\$exe_filename arg1"
|
||||
Fail-Json -obj $result -message "Test $test_name failed`nCommand should have thrown an exception"
|
||||
} catch {
|
||||
Assert-Equals -actual $_.Exception.Message -expected "Exception calling `"SearchPath`" with `"1`" argument(s): `"Could not find file 'C:\fakepath\$exe_filename'.`""
|
||||
}
|
||||
catch {
|
||||
$expected = "Exception calling `"SearchPath`" with `"1`" argument(s): `"Could not find file 'C:\fakepath\$exe_filename'.`""
|
||||
Assert-Equal -actual $_.Exception.Message -expected $expected
|
||||
}
|
||||
|
||||
$test_name = "exe in current folder"
|
||||
$actual = Run-Command -command "$exe_filename arg1" -working_directory $exe_directory
|
||||
Assert-Equals -actual $actual.rc -expected 0
|
||||
Assert-Equals -actual $actual.stdout -expected "arg1`r`n"
|
||||
Assert-Equals -actual $actual.stderr -expected ""
|
||||
Assert-Equals -actual $actual.executable -expected $exe
|
||||
Assert-Equal -actual $actual.rc -expected 0
|
||||
Assert-Equal -actual $actual.stdout -expected "arg1`r`n"
|
||||
Assert-Equal -actual $actual.stderr -expected ""
|
||||
Assert-Equal -actual $actual.executable -expected $exe
|
||||
|
||||
$test_name = "no working directory set"
|
||||
$actual = Run-Command -command "cmd.exe /c cd"
|
||||
Assert-Equals -actual $actual.rc -expected 0
|
||||
Assert-Equals -actual $actual.stdout -expected "$($pwd.Path)`r`n"
|
||||
Assert-Equals -actual $actual.stderr -expected ""
|
||||
Assert-Equals -actual $actual.executable.ToUpper() -expected "$env:SystemRoot\System32\cmd.exe".ToUpper()
|
||||
Assert-Equal -actual $actual.rc -expected 0
|
||||
Assert-Equal -actual $actual.stdout -expected "$($pwd.Path)`r`n"
|
||||
Assert-Equal -actual $actual.stderr -expected ""
|
||||
Assert-Equal -actual $actual.executable.ToUpper() -expected "$env:SystemRoot\System32\cmd.exe".ToUpper()
|
||||
|
||||
$test_name = "working directory override"
|
||||
$actual = Run-Command -command "cmd.exe /c cd" -working_directory $env:SystemRoot
|
||||
Assert-Equals -actual $actual.rc -expected 0
|
||||
Assert-Equals -actual $actual.stdout -expected "$env:SystemRoot`r`n"
|
||||
Assert-Equals -actual $actual.stderr -expected ""
|
||||
Assert-Equals -actual $actual.executable.ToUpper() -expected "$env:SystemRoot\System32\cmd.exe".ToUpper()
|
||||
Assert-Equal -actual $actual.rc -expected 0
|
||||
Assert-Equal -actual $actual.stdout -expected "$env:SystemRoot`r`n"
|
||||
Assert-Equal -actual $actual.stderr -expected ""
|
||||
Assert-Equal -actual $actual.executable.ToUpper() -expected "$env:SystemRoot\System32\cmd.exe".ToUpper()
|
||||
|
||||
$test_name = "working directory invalid path"
|
||||
try {
|
||||
$actual = Run-Command -command "doesn't matter" -working_directory "invalid path here"
|
||||
Fail-Json -obj $result -message "Test $test_name failed`nCommand should have thrown an exception"
|
||||
} catch {
|
||||
Assert-Equals -actual $_.Exception.Message -expected "invalid working directory path 'invalid path here'"
|
||||
}
|
||||
catch {
|
||||
Assert-Equal -actual $_.Exception.Message -expected "invalid working directory path 'invalid path here'"
|
||||
}
|
||||
|
||||
$test_name = "invalid arguments"
|
||||
$actual = Run-Command -command "ipconfig.exe /asdf"
|
||||
Assert-Equals -actual $actual.rc -expected 1
|
||||
Assert-Equal -actual $actual.rc -expected 1
|
||||
|
||||
$test_name = "test stdout and stderr streams"
|
||||
$actual = Run-Command -command "cmd.exe /c echo stdout && echo stderr 1>&2"
|
||||
Assert-Equals -actual $actual.rc -expected 0
|
||||
Assert-Equals -actual $actual.stdout -expected "stdout `r`n"
|
||||
Assert-Equals -actual $actual.stderr -expected "stderr `r`n"
|
||||
Assert-Equal -actual $actual.rc -expected 0
|
||||
Assert-Equal -actual $actual.stdout -expected "stdout `r`n"
|
||||
Assert-Equal -actual $actual.stderr -expected "stderr `r`n"
|
||||
|
||||
$test_name = "Test UTF8 output from stdout stream"
|
||||
$actual = Run-Command -command "powershell.exe -ExecutionPolicy ByPass -Command `"Write-Host '💩'`""
|
||||
Assert-Equals -actual $actual.rc -expected 0
|
||||
Assert-Equals -actual $actual.stdout -expected "💩`n"
|
||||
Assert-Equals -actual $actual.stderr -expected ""
|
||||
Assert-Equal -actual $actual.rc -expected 0
|
||||
Assert-Equal -actual $actual.stdout -expected "💩`n"
|
||||
Assert-Equal -actual $actual.stderr -expected ""
|
||||
|
||||
$test_name = "test default environment variable"
|
||||
Set-Item -LiteralPath env:TESTENV -Value "test"
|
||||
|
@ -129,7 +133,7 @@ begin {
|
|||
"@
|
||||
$encoded_wrapper = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($wrapper))
|
||||
$actual = Run-Command -command "powershell.exe -ExecutionPolicy ByPass -EncodedCommand $encoded_wrapper" -stdin "Ansible"
|
||||
Assert-Equals -actual $actual.stdout -expected "Ansible`n"
|
||||
Assert-Equal -actual $actual.stdout -expected "Ansible`n"
|
||||
|
||||
$result.data = "success"
|
||||
Exit-Json -obj $result
|
||||
|
|
|
@ -9,10 +9,13 @@ $result = @{
|
|||
changed = $false
|
||||
}
|
||||
|
||||
Function Assert-Equals($actual, $expected) {
|
||||
Function Assert-Equal($actual, $expected) {
|
||||
if ($actual -cne $expected) {
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$error_msg = "AssertionError:`r`nActual: `"$actual`" != Expected: `"$expected`"`r`nLine: $($call_stack.ScriptLineNumber), Method: $($call_stack.Position.Text)"
|
||||
$error_msg = -join @(
|
||||
"AssertionError:`r`nActual: `"$actual`" != Expected: `"$expected`"`r`nLine: "
|
||||
"$($call_stack.ScriptLineNumber), Method: $($call_stack.Position.Text)"
|
||||
)
|
||||
Fail-Json -obj $result -message $error_msg
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +25,8 @@ Function Get-PagefilePath() {
|
|||
$cs = Get-CimInstance -ClassName Win32_ComputerSystem
|
||||
if ($cs.AutomaticManagedPagefile) {
|
||||
$pagefile = "$($env:SystemRoot.Substring(0, 1)):\pagefile.sys"
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$pf = Get-CimInstance -ClassName Win32_PageFileSetting
|
||||
if ($null -ne $pf) {
|
||||
$pagefile = $pf[0].Name
|
||||
|
@ -35,74 +39,76 @@ $pagefile = Get-PagefilePath
|
|||
if ($pagefile) {
|
||||
# Test-AnsiblePath Hidden system file
|
||||
$actual = Test-AnsiblePath -Path $pagefile
|
||||
Assert-Equals -actual $actual -expected $true
|
||||
Assert-Equal -actual $actual -expected $true
|
||||
|
||||
# Get-AnsibleItem file
|
||||
$actual = Get-AnsibleItem -Path $pagefile
|
||||
Assert-Equals -actual $actual.FullName -expected $pagefile
|
||||
Assert-Equals -actual $actual.Attributes.HasFlag([System.IO.FileAttributes]::Directory) -expected $false
|
||||
Assert-Equals -actual $actual.Exists -expected $true
|
||||
Assert-Equal -actual $actual.FullName -expected $pagefile
|
||||
Assert-Equal -actual $actual.Attributes.HasFlag([System.IO.FileAttributes]::Directory) -expected $false
|
||||
Assert-Equal -actual $actual.Exists -expected $true
|
||||
}
|
||||
|
||||
# Test-AnsiblePath File that doesn't exist
|
||||
$actual = Test-AnsiblePath -Path C:\fakefile
|
||||
Assert-Equals -actual $actual -expected $false
|
||||
Assert-Equal -actual $actual -expected $false
|
||||
|
||||
# Test-AnsiblePath Directory that doesn't exist
|
||||
$actual = Test-AnsiblePath -Path C:\fakedirectory
|
||||
Assert-Equals -actual $actual -expected $false
|
||||
Assert-Equal -actual $actual -expected $false
|
||||
|
||||
# Test-AnsiblePath file in non-existant directory
|
||||
$actual = Test-AnsiblePath -Path C:\fakedirectory\fakefile.txt
|
||||
Assert-Equals -actual $actual -expected $false
|
||||
Assert-Equal -actual $actual -expected $false
|
||||
|
||||
# Test-AnsiblePath Normal directory
|
||||
$actual = Test-AnsiblePath -Path C:\Windows
|
||||
Assert-Equals -actual $actual -expected $true
|
||||
Assert-Equal -actual $actual -expected $true
|
||||
|
||||
# Test-AnsiblePath Normal file
|
||||
$actual = Test-AnsiblePath -Path C:\Windows\System32\kernel32.dll
|
||||
Assert-Equals -actual $actual -expected $true
|
||||
Assert-Equal -actual $actual -expected $true
|
||||
|
||||
# Test-AnsiblePath fails with wildcard
|
||||
$failed = $false
|
||||
try {
|
||||
Test-AnsiblePath -Path C:\Windows\*.exe
|
||||
} catch {
|
||||
$failed = $true
|
||||
Assert-Equals -actual $_.Exception.Message -expected "Exception calling `"GetAttributes`" with `"1`" argument(s): `"Illegal characters in path.`""
|
||||
}
|
||||
Assert-Equals -actual $failed -expected $true
|
||||
catch {
|
||||
$failed = $true
|
||||
Assert-Equal -actual $_.Exception.Message -expected "Exception calling `"GetAttributes`" with `"1`" argument(s): `"Illegal characters in path.`""
|
||||
}
|
||||
Assert-Equal -actual $failed -expected $true
|
||||
|
||||
# Test-AnsiblePath on non file PS Provider object
|
||||
$actual = Test-AnsiblePath -Path Cert:\LocalMachine\My
|
||||
Assert-Equals -actual $actual -expected $true
|
||||
Assert-Equal -actual $actual -expected $true
|
||||
|
||||
# Test-AnsiblePath on environment variable
|
||||
$actual = Test-AnsiblePath -Path env:SystemDrive
|
||||
Assert-Equals -actual $actual -expected $true
|
||||
Assert-Equal -actual $actual -expected $true
|
||||
|
||||
# Test-AnsiblePath on environment variable that does not exist
|
||||
$actual = Test-AnsiblePath -Path env:FakeEnvValue
|
||||
Assert-Equals -actual $actual -expected $false
|
||||
Assert-Equal -actual $actual -expected $false
|
||||
|
||||
# Get-AnsibleItem doesn't exist with -ErrorAction SilentlyContinue param
|
||||
$actual = Get-AnsibleItem -Path C:\fakefile -ErrorAction SilentlyContinue
|
||||
Assert-Equals -actual $actual -expected $null
|
||||
Assert-Equal -actual $actual -expected $null
|
||||
|
||||
# Get-AnsibleItem directory
|
||||
$actual = Get-AnsibleItem -Path C:\Windows
|
||||
Assert-Equals -actual $actual.FullName -expected C:\Windows
|
||||
Assert-Equals -actual $actual.Attributes.HasFlag([System.IO.FileAttributes]::Directory) -expected $true
|
||||
Assert-Equals -actual $actual.Exists -expected $true
|
||||
Assert-Equal -actual $actual.FullName -expected C:\Windows
|
||||
Assert-Equal -actual $actual.Attributes.HasFlag([System.IO.FileAttributes]::Directory) -expected $true
|
||||
Assert-Equal -actual $actual.Exists -expected $true
|
||||
|
||||
# ensure Get-AnsibleItem doesn't fail in a try/catch and -ErrorAction SilentlyContinue - stop's a trap from trapping it
|
||||
try {
|
||||
$actual = Get-AnsibleItem -Path C:\fakepath -ErrorAction SilentlyContinue
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
Fail-Json -obj $result -message "this should not fire"
|
||||
}
|
||||
Assert-Equals -actual $actual -expected $null
|
||||
Assert-Equal -actual $actual -expected $null
|
||||
|
||||
$result.data = "success"
|
||||
Exit-Json -obj $result
|
||||
|
|
|
@ -6,4 +6,4 @@ $params = Parse-Args $args
|
|||
|
||||
$path = Get-AnsibleParam -Obj $params -Name path -Type path
|
||||
|
||||
Exit-Json @{ path=$path }
|
||||
Exit-Json @{ path = $path }
|
||||
|
|
|
@ -25,7 +25,7 @@ New-Item -Path $folder_target -ItemType Directory | Out-Null
|
|||
New-Item -Path $file_target -ItemType File | Out-Null
|
||||
Set-Content -LiteralPath $file_target -Value "a"
|
||||
|
||||
Function Assert-Equals($actual, $expected) {
|
||||
Function Assert-Equal($actual, $expected) {
|
||||
if ($actual -ne $expected) {
|
||||
Fail-Json @{} "actual != expected`nActual: $actual`nExpected: $expected"
|
||||
}
|
||||
|
@ -48,105 +48,109 @@ Assert-True -expression ($null -eq $no_link_result) -message "did not return nul
|
|||
try {
|
||||
New-Link -link_path "$path\folder-hard" -link_target $folder_target -link_type "hard"
|
||||
Assert-True -expression $false -message "creation of hard link should have failed if target was a directory"
|
||||
} catch {
|
||||
Assert-Equals -actual $_.Exception.Message -expected "cannot set the target for a hard link to a directory"
|
||||
}
|
||||
catch {
|
||||
Assert-Equal -actual $_.Exception.Message -expected "cannot set the target for a hard link to a directory"
|
||||
}
|
||||
|
||||
# fail to create a junction point pointed to a file
|
||||
try {
|
||||
New-Link -link_path "$path\junction-fail" -link_target $file_target -link_type "junction"
|
||||
Assert-True -expression $false -message "creation of junction point should have failed if target was a file"
|
||||
} catch {
|
||||
Assert-Equals -actual $_.Exception.Message -expected "cannot set the target for a junction point to a file"
|
||||
}
|
||||
catch {
|
||||
Assert-Equal -actual $_.Exception.Message -expected "cannot set the target for a junction point to a file"
|
||||
}
|
||||
|
||||
# fail to create a symbolic link with non-existent target
|
||||
try {
|
||||
New-Link -link_path "$path\symlink-fail" -link_target "$path\fake-folder" -link_type "link"
|
||||
Assert-True -expression $false -message "creation of symbolic link should have failed if target did not exist"
|
||||
} catch {
|
||||
Assert-Equals -actual $_.Exception.Message -expected "link_target '$path\fake-folder' does not exist, cannot create link"
|
||||
}
|
||||
catch {
|
||||
Assert-Equal -actual $_.Exception.Message -expected "link_target '$path\fake-folder' does not exist, cannot create link"
|
||||
}
|
||||
|
||||
# create recursive symlink
|
||||
Run-Command -command "cmd.exe /c mklink /D symlink-rel folder" -working_directory $path | Out-Null
|
||||
$rel_link_result = Get-Link -link_path "$path\symlink-rel"
|
||||
Assert-Equals -actual $rel_link_result.Type -expected "SymbolicLink"
|
||||
Assert-Equals -actual $rel_link_result.SubstituteName -expected "folder"
|
||||
Assert-Equals -actual $rel_link_result.PrintName -expected "folder"
|
||||
Assert-Equals -actual $rel_link_result.TargetPath -expected "folder"
|
||||
Assert-Equals -actual $rel_link_result.AbsolutePath -expected $folder_target
|
||||
Assert-Equals -actual $rel_link_result.HardTargets -expected $null
|
||||
Assert-Equal -actual $rel_link_result.Type -expected "SymbolicLink"
|
||||
Assert-Equal -actual $rel_link_result.SubstituteName -expected "folder"
|
||||
Assert-Equal -actual $rel_link_result.PrintName -expected "folder"
|
||||
Assert-Equal -actual $rel_link_result.TargetPath -expected "folder"
|
||||
Assert-Equal -actual $rel_link_result.AbsolutePath -expected $folder_target
|
||||
Assert-Equal -actual $rel_link_result.HardTargets -expected $null
|
||||
|
||||
# create a symbolic file test
|
||||
New-Link -link_path $symlink_file_path -link_target $file_target -link_type "link"
|
||||
$file_link_result = Get-Link -link_path $symlink_file_path
|
||||
Assert-Equals -actual $file_link_result.Type -expected "SymbolicLink"
|
||||
Assert-Equals -actual $file_link_result.SubstituteName -expected "\??\$file_target"
|
||||
Assert-Equals -actual $file_link_result.PrintName -expected $file_target
|
||||
Assert-Equals -actual $file_link_result.TargetPath -expected $file_target
|
||||
Assert-Equals -actual $file_link_result.AbsolutePath -expected $file_target
|
||||
Assert-Equals -actual $file_link_result.HardTargets -expected $null
|
||||
Assert-Equal -actual $file_link_result.Type -expected "SymbolicLink"
|
||||
Assert-Equal -actual $file_link_result.SubstituteName -expected "\??\$file_target"
|
||||
Assert-Equal -actual $file_link_result.PrintName -expected $file_target
|
||||
Assert-Equal -actual $file_link_result.TargetPath -expected $file_target
|
||||
Assert-Equal -actual $file_link_result.AbsolutePath -expected $file_target
|
||||
Assert-Equal -actual $file_link_result.HardTargets -expected $null
|
||||
|
||||
# create a symbolic link folder test
|
||||
New-Link -link_path $symlink_folder_path -link_target $folder_target -link_type "link"
|
||||
$folder_link_result = Get-Link -link_path $symlink_folder_path
|
||||
Assert-Equals -actual $folder_link_result.Type -expected "SymbolicLink"
|
||||
Assert-Equals -actual $folder_link_result.SubstituteName -expected "\??\$folder_target"
|
||||
Assert-Equals -actual $folder_link_result.PrintName -expected $folder_target
|
||||
Assert-Equals -actual $folder_link_result.TargetPath -expected $folder_target
|
||||
Assert-Equals -actual $folder_link_result.AbsolutePath -expected $folder_target
|
||||
Assert-Equals -actual $folder_link_result.HardTargets -expected $null
|
||||
Assert-Equal -actual $folder_link_result.Type -expected "SymbolicLink"
|
||||
Assert-Equal -actual $folder_link_result.SubstituteName -expected "\??\$folder_target"
|
||||
Assert-Equal -actual $folder_link_result.PrintName -expected $folder_target
|
||||
Assert-Equal -actual $folder_link_result.TargetPath -expected $folder_target
|
||||
Assert-Equal -actual $folder_link_result.AbsolutePath -expected $folder_target
|
||||
Assert-Equal -actual $folder_link_result.HardTargets -expected $null
|
||||
|
||||
# create a junction point test
|
||||
New-Link -link_path $junction_point_path -link_target $folder_target -link_type "junction"
|
||||
$junction_point_result = Get-Link -link_path $junction_point_path
|
||||
Assert-Equals -actual $junction_point_result.Type -expected "JunctionPoint"
|
||||
Assert-Equals -actual $junction_point_result.SubstituteName -expected "\??\$folder_target"
|
||||
Assert-Equals -actual $junction_point_result.PrintName -expected $folder_target
|
||||
Assert-Equals -actual $junction_point_result.TargetPath -expected $folder_target
|
||||
Assert-Equals -actual $junction_point_result.AbsolutePath -expected $folder_target
|
||||
Assert-Equals -actual $junction_point_result.HardTargets -expected $null
|
||||
Assert-Equal -actual $junction_point_result.Type -expected "JunctionPoint"
|
||||
Assert-Equal -actual $junction_point_result.SubstituteName -expected "\??\$folder_target"
|
||||
Assert-Equal -actual $junction_point_result.PrintName -expected $folder_target
|
||||
Assert-Equal -actual $junction_point_result.TargetPath -expected $folder_target
|
||||
Assert-Equal -actual $junction_point_result.AbsolutePath -expected $folder_target
|
||||
Assert-Equal -actual $junction_point_result.HardTargets -expected $null
|
||||
|
||||
# create a hard link test
|
||||
New-Link -link_path $hardlink_path -link_target $file_target -link_type "hard"
|
||||
$hardlink_result = Get-Link -link_path $hardlink_path
|
||||
Assert-Equals -actual $hardlink_result.Type -expected "HardLink"
|
||||
Assert-Equals -actual $hardlink_result.SubstituteName -expected $null
|
||||
Assert-Equals -actual $hardlink_result.PrintName -expected $null
|
||||
Assert-Equals -actual $hardlink_result.TargetPath -expected $null
|
||||
Assert-Equals -actual $hardlink_result.AbsolutePath -expected $null
|
||||
Assert-Equal -actual $hardlink_result.Type -expected "HardLink"
|
||||
Assert-Equal -actual $hardlink_result.SubstituteName -expected $null
|
||||
Assert-Equal -actual $hardlink_result.PrintName -expected $null
|
||||
Assert-Equal -actual $hardlink_result.TargetPath -expected $null
|
||||
Assert-Equal -actual $hardlink_result.AbsolutePath -expected $null
|
||||
if ($hardlink_result.HardTargets[0] -ne $hardlink_path -and $hardlink_result.HardTargets[1] -ne $hardlink_path) {
|
||||
Assert-True -expression $false -message "file $hardlink_path is not a target of the hard link"
|
||||
}
|
||||
if ($hardlink_result.HardTargets[0] -ne $file_target -and $hardlink_result.HardTargets[1] -ne $file_target) {
|
||||
Assert-True -expression $false -message "file $file_target is not a target of the hard link"
|
||||
}
|
||||
Assert-equals -actual (Get-Content -LiteralPath $hardlink_path -Raw) -expected (Get-Content -LiteralPath $file_target -Raw)
|
||||
Assert-Equal -actual (Get-Content -LiteralPath $hardlink_path -Raw) -expected (Get-Content -LiteralPath $file_target -Raw)
|
||||
|
||||
# create a new hard link and verify targets go to 3
|
||||
New-Link -link_path $hardlink_path_2 -link_target $file_target -link_type "hard"
|
||||
$hardlink_result_2 = Get-Link -link_path $hardlink_path
|
||||
Assert-True -expression ($hardlink_result_2.HardTargets.Count -eq 3) -message "did not return 3 targets for the hard link, actual $($hardlink_result_2.Targets.Count)"
|
||||
$expected = "did not return 3 targets for the hard link, actual $($hardlink_result_2.Targets.Count)"
|
||||
Assert-True -expression ($hardlink_result_2.HardTargets.Count -eq 3) -message $expected
|
||||
|
||||
# check if broken symbolic link still works
|
||||
Remove-Item -LiteralPath $folder_target -Force | Out-Null
|
||||
$broken_link_result = Get-Link -link_path $symlink_folder_path
|
||||
Assert-Equals -actual $broken_link_result.Type -expected "SymbolicLink"
|
||||
Assert-Equals -actual $broken_link_result.SubstituteName -expected "\??\$folder_target"
|
||||
Assert-Equals -actual $broken_link_result.PrintName -expected $folder_target
|
||||
Assert-Equals -actual $broken_link_result.TargetPath -expected $folder_target
|
||||
Assert-Equals -actual $broken_link_result.AbsolutePath -expected $folder_target
|
||||
Assert-Equals -actual $broken_link_result.HardTargets -expected $null
|
||||
Assert-Equal -actual $broken_link_result.Type -expected "SymbolicLink"
|
||||
Assert-Equal -actual $broken_link_result.SubstituteName -expected "\??\$folder_target"
|
||||
Assert-Equal -actual $broken_link_result.PrintName -expected $folder_target
|
||||
Assert-Equal -actual $broken_link_result.TargetPath -expected $folder_target
|
||||
Assert-Equal -actual $broken_link_result.AbsolutePath -expected $folder_target
|
||||
Assert-Equal -actual $broken_link_result.HardTargets -expected $null
|
||||
|
||||
# check if broken junction point still works
|
||||
$broken_junction_result = Get-Link -link_path $junction_point_path
|
||||
Assert-Equals -actual $broken_junction_result.Type -expected "JunctionPoint"
|
||||
Assert-Equals -actual $broken_junction_result.SubstituteName -expected "\??\$folder_target"
|
||||
Assert-Equals -actual $broken_junction_result.PrintName -expected $folder_target
|
||||
Assert-Equals -actual $broken_junction_result.TargetPath -expected $folder_target
|
||||
Assert-Equals -actual $broken_junction_result.AbsolutePath -expected $folder_target
|
||||
Assert-Equals -actual $broken_junction_result.HardTargets -expected $null
|
||||
Assert-Equal -actual $broken_junction_result.Type -expected "JunctionPoint"
|
||||
Assert-Equal -actual $broken_junction_result.SubstituteName -expected "\??\$folder_target"
|
||||
Assert-Equal -actual $broken_junction_result.PrintName -expected $folder_target
|
||||
Assert-Equal -actual $broken_junction_result.TargetPath -expected $folder_target
|
||||
Assert-Equal -actual $broken_junction_result.AbsolutePath -expected $folder_target
|
||||
Assert-Equal -actual $broken_junction_result.HardTargets -expected $null
|
||||
|
||||
# delete file symbolic link
|
||||
Remove-Link -link_path $symlink_file_path
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
$module = [Ansible.Basic.AnsibleModule]::Create($args, @{})
|
||||
|
||||
Function Assert-Equals($actual, $expected) {
|
||||
Function Assert-Equal($actual, $expected) {
|
||||
if ($actual -cne $expected) {
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.actual = $actual
|
||||
|
@ -70,20 +70,21 @@ foreach ($privilege in $total_privileges) {
|
|||
$expected = $actual_privileges.$privilege
|
||||
}
|
||||
$actual = Get-AnsiblePrivilege -Name $privilege
|
||||
Assert-Equals -actual $actual -expected $expected
|
||||
Assert-Equal -actual $actual -expected $expected
|
||||
}
|
||||
|
||||
# test c# GetAllPrivilegeInfo
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
Assert-Equals -actual $actual.GetType().Name -expected 'Dictionary`2'
|
||||
Assert-Equals -actual $actual.Count -expected $actual_privileges.Count
|
||||
Assert-Equal -actual $actual.GetType().Name -expected 'Dictionary`2'
|
||||
Assert-Equal -actual $actual.Count -expected $actual_privileges.Count
|
||||
foreach ($privilege in $total_privileges) {
|
||||
if ($actual_privileges.ContainsKey($privilege)) {
|
||||
$actual_value = $actual.$privilege
|
||||
if ($actual_privileges.$privilege) {
|
||||
Assert-Equals -actual $actual_value.HasFlag([Ansible.Privilege.PrivilegeAttributes]::Enabled) -expected $true
|
||||
} else {
|
||||
Assert-Equals -actual $actual_value.HasFlag([Ansible.Privilege.PrivilegeAttributes]::Enabled) -expected $false
|
||||
Assert-Equal -actual $actual_value.HasFlag([Ansible.Privilege.PrivilegeAttributes]::Enabled) -expected $true
|
||||
}
|
||||
else {
|
||||
Assert-Equal -actual $actual_value.HasFlag([Ansible.Privilege.PrivilegeAttributes]::Enabled) -expected $false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,19 +94,19 @@ Set-AnsiblePrivilege -Name SeUndockPrivilege -Value $false # ensure we start wi
|
|||
|
||||
Set-AnsiblePrivilege -Name SeUndockPrivilege -Value $true -WhatIf
|
||||
$actual = Get-AnsiblePrivilege -Name SeUndockPrivilege
|
||||
Assert-Equals -actual $actual -expected $false
|
||||
Assert-Equal -actual $actual -expected $false
|
||||
|
||||
Set-AnsiblePrivilege -Name SeUndockPrivilege -Value $true
|
||||
$actual = Get-AnsiblePrivilege -Name SeUndockPrivilege
|
||||
Assert-Equals -actual $actual -expected $true
|
||||
Assert-Equal -actual $actual -expected $true
|
||||
|
||||
Set-AnsiblePrivilege -Name SeUndockPrivilege -Value $false -WhatIf
|
||||
$actual = Get-AnsiblePrivilege -Name SeUndockPrivilege
|
||||
Assert-Equals -actual $actual -expected $true
|
||||
Assert-Equal -actual $actual -expected $true
|
||||
|
||||
Set-AnsiblePrivilege -Name SeUndockPrivilege -Value $false
|
||||
$actual = Get-AnsiblePrivilege -Name SeUndockPrivilege
|
||||
Assert-Equals -actual $actual -expected $false
|
||||
Assert-Equal -actual $actual -expected $false
|
||||
|
||||
$module.Result.data = "success"
|
||||
$module.ExitJson()
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
$params = Parse-Args $args
|
||||
$sid_account = Get-AnsibleParam -obj $params -name "sid_account" -type "str" -failifempty $true
|
||||
|
||||
Function Assert-Equals($actual, $expected) {
|
||||
Function Assert-Equal($actual, $expected) {
|
||||
if ($actual -ne $expected) {
|
||||
Fail-Json @{} "actual != expected`nActual: $actual`nExpected: $expected"
|
||||
}
|
||||
|
@ -39,10 +39,18 @@ $tests = @(
|
|||
@{ sid = "S-1-1-0"; full_name = "Everyone"; names = @("Everyone") },
|
||||
@{ sid = "S-1-5-18"; full_name = "NT AUTHORITY\SYSTEM"; names = @("NT AUTHORITY\SYSTEM", "SYSTEM") },
|
||||
@{ sid = "S-1-5-20"; full_name = "NT AUTHORITY\NETWORK SERVICE"; names = @("NT AUTHORITY\NETWORK SERVICE", "NETWORK SERVICE") },
|
||||
@{ sid = "$($default_admin.SID)"; full_name = "$($default_admin.FullName)"; names = @("$env:COMPUTERNAME\$($default_admin.Name)", "$($default_admin.Name)", ".\$($default_admin.Name)") },
|
||||
@{
|
||||
sid = "$($default_admin.SID)"
|
||||
full_name = "$($default_admin.FullName)"
|
||||
names = @("$env:COMPUTERNAME\$($default_admin.Name)", "$($default_admin.Name)", ".\$($default_admin.Name)")
|
||||
},
|
||||
|
||||
# Local Groups
|
||||
@{ sid = "$($default_admin_group.SID)"; full_name = "BUILTIN\$($default_admin_group.Name)"; names = @("BUILTIN\$($default_admin_group.Name)", "$($default_admin_group.Name)", ".\$($default_admin_group.Name)") }
|
||||
@{
|
||||
sid = "$($default_admin_group.SID)"
|
||||
full_name = "BUILTIN\$($default_admin_group.Name)"
|
||||
names = @("BUILTIN\$($default_admin_group.Name)", "$($default_admin_group.Name)", ".\$($default_admin_group.Name)")
|
||||
}
|
||||
)
|
||||
|
||||
# Add domain tests if the domain name has been set
|
||||
|
@ -70,12 +78,12 @@ foreach ($test in $tests) {
|
|||
$actual_account_name = Convert-FromSID -sid $test.sid
|
||||
# renamed admins may have an empty FullName; skip comparison in that case
|
||||
if ($test.full_name) {
|
||||
Assert-Equals -actual $actual_account_name -expected $test.full_name
|
||||
Assert-Equal -actual $actual_account_name -expected $test.full_name
|
||||
}
|
||||
|
||||
foreach ($test_name in $test.names) {
|
||||
$actual_sid = Convert-ToSID -account_name $test_name
|
||||
Assert-Equals -actual $actual_sid -expected $test.sid
|
||||
Assert-Equal -actual $actual_sid -expected $test.sid
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,11 +91,11 @@ foreach ($test in $tests) {
|
|||
# in the normal test suite
|
||||
# Calling Convert-ToSID with a string like a SID should return that SID back
|
||||
$actual = Convert-ToSID -account_name $sid_account
|
||||
Assert-Equals -actual $actual -expected $sid_account
|
||||
Assert-Equal -actual $actual -expected $sid_account
|
||||
|
||||
# Calling COnvert-ToSID with a string prefixed with .\ should return the SID
|
||||
# for a user that is called that SID and not the SID passed in
|
||||
$actual = Convert-ToSID -account_name ".\$sid_account"
|
||||
Assert-Equals -actual ($actual -ne $sid_account) -expected $true
|
||||
Assert-Equal -actual ($actual -ne $sid_account) -expected $true
|
||||
|
||||
Exit-Json @{ data = "success" }
|
||||
|
|
|
@ -13,45 +13,48 @@ $module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
|
|||
|
||||
$httpbin_host = $module.Params.httpbin_host
|
||||
|
||||
Function Assert-Equals {
|
||||
Function Assert-Equal {
|
||||
param(
|
||||
[Parameter(Mandatory=$true, ValueFromPipeline=$true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory=$true, Position=0)][AllowNull()]$Expected
|
||||
[Parameter(Mandatory = $true, ValueFromPipeline = $true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory = $true, Position = 0)][AllowNull()]$Expected
|
||||
)
|
||||
|
||||
$matched = $false
|
||||
if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array] -or $Actual -is [System.Collections.IList]) {
|
||||
$Actual.Count | Assert-Equals -Expected $Expected.Count
|
||||
for ($i = 0; $i -lt $Actual.Count; $i++) {
|
||||
$actualValue = $Actual[$i]
|
||||
$expectedValue = $Expected[$i]
|
||||
Assert-Equals -Actual $actualValue -Expected $expectedValue
|
||||
process {
|
||||
$matched = $false
|
||||
if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array] -or $Actual -is [System.Collections.IList]) {
|
||||
$Actual.Count | Assert-Equal -Expected $Expected.Count
|
||||
for ($i = 0; $i -lt $Actual.Count; $i++) {
|
||||
$actualValue = $Actual[$i]
|
||||
$expectedValue = $Expected[$i]
|
||||
Assert-Equal -Actual $actualValue -Expected $expectedValue
|
||||
}
|
||||
$matched = $true
|
||||
}
|
||||
$matched = $true
|
||||
} else {
|
||||
$matched = $Actual -ceq $Expected
|
||||
}
|
||||
|
||||
if (-not $matched) {
|
||||
if ($Actual -is [PSObject]) {
|
||||
$Actual = $Actual.ToString()
|
||||
else {
|
||||
$matched = $Actual -ceq $Expected
|
||||
}
|
||||
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.test = $test
|
||||
$module.Result.actual = $Actual
|
||||
$module.Result.expected = $Expected
|
||||
$module.Result.line = $call_stack.ScriptLineNumber
|
||||
$module.Result.method = $call_stack.Position.Text
|
||||
if (-not $matched) {
|
||||
if ($Actual -is [PSObject]) {
|
||||
$Actual = $Actual.ToString()
|
||||
}
|
||||
|
||||
$module.FailJson("AssertionError: actual != expected")
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.test = $test
|
||||
$module.Result.actual = $Actual
|
||||
$module.Result.expected = $Expected
|
||||
$module.Result.line = $call_stack.ScriptLineNumber
|
||||
$module.Result.method = $call_stack.Position.Text
|
||||
|
||||
$module.FailJson("AssertionError: actual != expected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Function Convert-StreamToString {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[Parameter(Mandatory = $true)]
|
||||
[System.IO.Stream]
|
||||
$Stream
|
||||
)
|
||||
|
@ -60,7 +63,8 @@ Function Convert-StreamToString {
|
|||
try {
|
||||
$Stream.CopyTo($ms)
|
||||
[System.Text.Encoding]::UTF8.GetString($ms.ToArray())
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
$ms.Dispose()
|
||||
}
|
||||
}
|
||||
|
@ -69,50 +73,50 @@ $tests = [Ordered]@{
|
|||
'GET request over http' = {
|
||||
$r = Get-AnsibleWebRequest -Uri "http://$httpbin_host/get"
|
||||
|
||||
$r.Method | Assert-Equals -Expected 'GET'
|
||||
$r.Timeout | Assert-Equals -Expected 30000
|
||||
$r.UseDefaultCredentials | Assert-Equals -Expected $false
|
||||
$r.Credentials | Assert-Equals -Expected $null
|
||||
$r.ClientCertificates.Count | Assert-Equals -Expected 0
|
||||
$r.Proxy.Credentials | Assert-Equals -Expected $null
|
||||
$r.UserAgent | Assert-Equals -Expected 'ansible-httpget'
|
||||
$r.Method | Assert-Equal -Expected 'GET'
|
||||
$r.Timeout | Assert-Equal -Expected 30000
|
||||
$r.UseDefaultCredentials | Assert-Equal -Expected $false
|
||||
$r.Credentials | Assert-Equal -Expected $null
|
||||
$r.ClientCertificates.Count | Assert-Equal -Expected 0
|
||||
$r.Proxy.Credentials | Assert-Equal -Expected $null
|
||||
$r.UserAgent | Assert-Equal -Expected 'ansible-httpget'
|
||||
|
||||
$actual = Invoke-WithWebRequest -Module $module -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.StatusCode | Assert-Equals -Expected 200
|
||||
$Response.StatusCode | Assert-Equal -Expected 200
|
||||
Convert-StreamToString -Stream $Stream
|
||||
} | ConvertFrom-Json
|
||||
|
||||
$actual.headers.'User-Agent' | Assert-Equals -Expected 'ansible-httpget'
|
||||
$actual.headers.'Host' | Assert-Equals -Expected $httpbin_host
|
||||
$actual.headers.'User-Agent' | Assert-Equal -Expected 'ansible-httpget'
|
||||
$actual.headers.'Host' | Assert-Equal -Expected $httpbin_host
|
||||
|
||||
$module.Result.msg | Assert-Equals -Expected 'OK'
|
||||
$module.Result.status_code | Assert-Equals -Expected 200
|
||||
$module.Result.ContainsKey('elapsed') | Assert-Equals -Expected $true
|
||||
$module.Result.msg | Assert-Equal -Expected 'OK'
|
||||
$module.Result.status_code | Assert-Equal -Expected 200
|
||||
$module.Result.ContainsKey('elapsed') | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
'GET request over https' = {
|
||||
# url is an alias for the -Uri parameter.
|
||||
$r = Get-AnsibleWebRequest -url "https://$httpbin_host/get"
|
||||
|
||||
$r.Method | Assert-Equals -Expected 'GET'
|
||||
$r.Timeout | Assert-Equals -Expected 30000
|
||||
$r.UseDefaultCredentials | Assert-Equals -Expected $false
|
||||
$r.Credentials | Assert-Equals -Expected $null
|
||||
$r.ClientCertificates.Count | Assert-Equals -Expected 0
|
||||
$r.Proxy.Credentials | Assert-Equals -Expected $null
|
||||
$r.UserAgent | Assert-Equals -Expected 'ansible-httpget'
|
||||
$r.Method | Assert-Equal -Expected 'GET'
|
||||
$r.Timeout | Assert-Equal -Expected 30000
|
||||
$r.UseDefaultCredentials | Assert-Equal -Expected $false
|
||||
$r.Credentials | Assert-Equal -Expected $null
|
||||
$r.ClientCertificates.Count | Assert-Equal -Expected 0
|
||||
$r.Proxy.Credentials | Assert-Equal -Expected $null
|
||||
$r.UserAgent | Assert-Equal -Expected 'ansible-httpget'
|
||||
|
||||
$actual = Invoke-WithWebRequest -Module $module -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.StatusCode | Assert-Equals -Expected 200
|
||||
$Response.StatusCode | Assert-Equal -Expected 200
|
||||
Convert-StreamToString -Stream $Stream
|
||||
} | ConvertFrom-Json
|
||||
|
||||
$actual.headers.'User-Agent' | Assert-Equals -Expected 'ansible-httpget'
|
||||
$actual.headers.'Host' | Assert-Equals -Expected $httpbin_host
|
||||
$actual.headers.'User-Agent' | Assert-Equal -Expected 'ansible-httpget'
|
||||
$actual.headers.'Host' | Assert-Equal -Expected $httpbin_host
|
||||
}
|
||||
|
||||
'POST request' = {
|
||||
|
@ -125,14 +129,14 @@ $tests = [Ordered]@{
|
|||
}
|
||||
$r = Get-AnsibleWebRequest @getParams
|
||||
|
||||
$r.Method | Assert-Equals -Expected 'POST'
|
||||
$r.Timeout | Assert-Equals -Expected 30000
|
||||
$r.UseDefaultCredentials | Assert-Equals -Expected $false
|
||||
$r.Credentials | Assert-Equals -Expected $null
|
||||
$r.ClientCertificates.Count | Assert-Equals -Expected 0
|
||||
$r.Proxy.Credentials | Assert-Equals -Expected $null
|
||||
$r.ContentType | Assert-Equals -Expected 'application/json'
|
||||
$r.UserAgent | Assert-Equals -Expected 'ansible-httpget'
|
||||
$r.Method | Assert-Equal -Expected 'POST'
|
||||
$r.Timeout | Assert-Equal -Expected 30000
|
||||
$r.UseDefaultCredentials | Assert-Equal -Expected $false
|
||||
$r.Credentials | Assert-Equal -Expected $null
|
||||
$r.ClientCertificates.Count | Assert-Equal -Expected 0
|
||||
$r.Proxy.Credentials | Assert-Equal -Expected $null
|
||||
$r.ContentType | Assert-Equal -Expected 'application/json'
|
||||
$r.UserAgent | Assert-Equal -Expected 'ansible-httpget'
|
||||
|
||||
$body = New-Object -TypeName System.IO.MemoryStream -ArgumentList @(,
|
||||
([System.Text.Encoding]::UTF8.GetBytes('{"foo":"bar"}'))
|
||||
|
@ -140,13 +144,13 @@ $tests = [Ordered]@{
|
|||
$actual = Invoke-WithWebRequest -Module $module -Request $r -Body $body -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.StatusCode | Assert-Equals -Expected 200
|
||||
$Response.StatusCode | Assert-Equal -Expected 200
|
||||
Convert-StreamToString -Stream $Stream
|
||||
} | ConvertFrom-Json
|
||||
|
||||
$actual.headers.'User-Agent' | Assert-Equals -Expected 'ansible-httpget'
|
||||
$actual.headers.'Host' | Assert-Equals -Expected $httpbin_host
|
||||
$actual.data | Assert-Equals -Expected '{"foo":"bar"}'
|
||||
$actual.headers.'User-Agent' | Assert-Equal -Expected 'ansible-httpget'
|
||||
$actual.headers.'Host' | Assert-Equal -Expected $httpbin_host
|
||||
$actual.data | Assert-Equal -Expected '{"foo":"bar"}'
|
||||
}
|
||||
|
||||
'Safe redirection of GET' = {
|
||||
|
@ -155,8 +159,8 @@ $tests = [Ordered]@{
|
|||
Invoke-WithWebRequest -Module $module -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.ResponseUri | Assert-Equals -Expected "http://$httpbin_host/get"
|
||||
$Response.StatusCode | Assert-Equals -Expected 200
|
||||
$Response.ResponseUri | Assert-Equal -Expected "http://$httpbin_host/get"
|
||||
$Response.StatusCode | Assert-Equal -Expected 200
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,8 +170,8 @@ $tests = [Ordered]@{
|
|||
Invoke-WithWebRequest -Module $module -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.ResponseUri | Assert-Equals -Expected "http://$httpbin_host/get"
|
||||
$Response.StatusCode | Assert-Equals -Expected 200
|
||||
$Response.ResponseUri | Assert-Equal -Expected "http://$httpbin_host/get"
|
||||
$Response.StatusCode | Assert-Equal -Expected 200
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,8 +185,8 @@ $tests = [Ordered]@{
|
|||
Invoke-WithWebRequest -Module $module -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.ResponseUri | Assert-Equals -Expected $r.RequestUri
|
||||
$Response.StatusCode | Assert-Equals -Expected 302
|
||||
$Response.ResponseUri | Assert-Equal -Expected $r.RequestUri
|
||||
$Response.StatusCode | Assert-Equal -Expected 302
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,8 +200,8 @@ $tests = [Ordered]@{
|
|||
Invoke-WithWebRequest -Module $module -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.ResponseUri | Assert-Equals -Expected $r.RequestUri
|
||||
$Response.StatusCode | Assert-Equals -Expected 302
|
||||
$Response.ResponseUri | Assert-Equal -Expected $r.RequestUri
|
||||
$Response.StatusCode | Assert-Equal -Expected 302
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,8 +216,8 @@ $tests = [Ordered]@{
|
|||
Invoke-WithWebRequest -Module $module -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.ResponseUri | Assert-Equals -Expected $r.RequestUri
|
||||
$Response.StatusCode | Assert-Equals -Expected 302
|
||||
$Response.ResponseUri | Assert-Equal -Expected $r.RequestUri
|
||||
$Response.StatusCode | Assert-Equal -Expected 302
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,8 +232,8 @@ $tests = [Ordered]@{
|
|||
Invoke-WithWebRequest -Module $module -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.ResponseUri | Assert-Equals -Expected $r.RequestUri
|
||||
$Response.StatusCode | Assert-Equals -Expected 302
|
||||
$Response.ResponseUri | Assert-Equal -Expected $r.RequestUri
|
||||
$Response.StatusCode | Assert-Equal -Expected 302
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,8 +247,8 @@ $tests = [Ordered]@{
|
|||
Invoke-WithWebRequest -Module $module -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.ResponseUri | Assert-Equals -Expected "http://$httpbin_host/get"
|
||||
$Response.StatusCode | Assert-Equals -Expected 200
|
||||
$Response.ResponseUri | Assert-Equal -Expected "http://$httpbin_host/get"
|
||||
$Response.StatusCode | Assert-Equal -Expected 200
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,8 +263,8 @@ $tests = [Ordered]@{
|
|||
Invoke-WithWebRequest -Module $module -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.ResponseUri | Assert-Equals -Expected "http://$httpbin_host/get"
|
||||
$Response.StatusCode | Assert-Equals -Expected 200
|
||||
$Response.ResponseUri | Assert-Equal -Expected "http://$httpbin_host/get"
|
||||
$Response.StatusCode | Assert-Equal -Expected 200
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,8 +279,8 @@ $tests = [Ordered]@{
|
|||
Invoke-WithWebRequest -Module $module -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.ResponseUri | Assert-Equals -Expected "https://$httpbin_host/put"
|
||||
$Response.StatusCode | Assert-Equals -Expected 200
|
||||
$Response.ResponseUri | Assert-Equal -Expected "https://$httpbin_host/put"
|
||||
$Response.StatusCode | Assert-Equal -Expected 200
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,8 +294,8 @@ $tests = [Ordered]@{
|
|||
Invoke-WithWebRequest -Module $module -Request $r -IgnoreBadResponse -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.ResponseUri | Assert-Equals -Expected "https://$httpbin_host/relative-redirect/1"
|
||||
$Response.StatusCode | Assert-Equals -Expected 302
|
||||
$Response.ResponseUri | Assert-Equal -Expected "https://$httpbin_host/relative-redirect/1"
|
||||
$Response.StatusCode | Assert-Equal -Expected 302
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,12 +309,13 @@ $tests = [Ordered]@{
|
|||
$failed = $false
|
||||
try {
|
||||
$null = Invoke-WithWebRequest -Module $module -Request $r -Script {}
|
||||
} catch {
|
||||
$_.Exception.GetType().Name | Assert-Equals -Expected 'WebException'
|
||||
$_.Exception.Message | Assert-Equals -Expected 'Too many automatic redirections were attempted.'
|
||||
}
|
||||
catch {
|
||||
$_.Exception.GetType().Name | Assert-Equal -Expected 'WebException'
|
||||
$_.Exception.Message | Assert-Equal -Expected 'Too many automatic redirections were attempted.'
|
||||
$failed = $true
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
'Basic auth as Credential' = {
|
||||
|
@ -324,7 +329,7 @@ $tests = [Ordered]@{
|
|||
Invoke-WithWebRequest -Module $module -Request $r -IgnoreBadResponse -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.StatusCode | Assert-Equals -Expected 200
|
||||
$Response.StatusCode | Assert-Equal -Expected 200
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -340,7 +345,7 @@ $tests = [Ordered]@{
|
|||
Invoke-WithWebRequest -Module $module -Request $r -IgnoreBadResponse -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.StatusCode | Assert-Equals -Expected 200
|
||||
$Response.StatusCode | Assert-Equal -Expected 200
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -359,13 +364,13 @@ $tests = [Ordered]@{
|
|||
$actual = Invoke-WithWebRequest -Module $module -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.StatusCode | Assert-Equals -Expected 200
|
||||
$Response.StatusCode | Assert-Equal -Expected 200
|
||||
Convert-StreamToString -Stream $Stream
|
||||
} | ConvertFrom-Json
|
||||
|
||||
$actual.headers.'Testheader' | Assert-Equals -Expected 'test-header'
|
||||
$actual.headers.'testingheader' | Assert-Equals -Expected 'testing_header'
|
||||
$actual.Headers.'User-Agent' | Assert-Equals -Expected 'test-agent'
|
||||
$actual.headers.'Testheader' | Assert-Equal -Expected 'test-header'
|
||||
$actual.headers.'testingheader' | Assert-Equal -Expected 'testing_header'
|
||||
$actual.Headers.'User-Agent' | Assert-Equal -Expected 'test-agent'
|
||||
}
|
||||
|
||||
'Request with timeout' = {
|
||||
|
@ -378,12 +383,13 @@ $tests = [Ordered]@{
|
|||
$failed = $false
|
||||
try {
|
||||
$null = Invoke-WithWebRequest -Module $module -Request $r -Script {}
|
||||
} catch {
|
||||
$failed = $true
|
||||
$_.Exception.GetType().Name | Assert-Equals -Expected WebException
|
||||
$_.Exception.Message | Assert-Equals -Expected 'The operation has timed out'
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
catch {
|
||||
$failed = $true
|
||||
$_.Exception.GetType().Name | Assert-Equal -Expected WebException
|
||||
$_.Exception.Message | Assert-Equal -Expected 'The operation has timed out'
|
||||
}
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
'Request with file URI' = {
|
||||
|
@ -395,12 +401,12 @@ $tests = [Ordered]@{
|
|||
$actual = Invoke-WithWebRequest -Module $module -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.ContentLength | Assert-Equals -Expected 6
|
||||
$Response.ContentLength | Assert-Equal -Expected 6
|
||||
Convert-StreamToString -Stream $Stream
|
||||
}
|
||||
$actual | Assert-Equals -Expected "test`r`n"
|
||||
$module.Result.msg | Assert-Equals -Expected "OK"
|
||||
$module.Result.status_code | Assert-Equals -Expected 200
|
||||
$actual | Assert-Equal -Expected "test`r`n"
|
||||
$module.Result.msg | Assert-Equal -Expected "OK"
|
||||
$module.Result.status_code | Assert-Equal -Expected 200
|
||||
}
|
||||
|
||||
'Web request based on module options' = {
|
||||
|
@ -419,9 +425,9 @@ $tests = [Ordered]@{
|
|||
$spec = @{
|
||||
options = @{
|
||||
url = @{ type = 'str'; required = $true }
|
||||
test = @{ type = 'str'; choices = 'abc', 'def'}
|
||||
test = @{ type = 'str'; choices = 'abc', 'def' }
|
||||
}
|
||||
mutually_exclusive = @(,@('url', 'test'))
|
||||
mutually_exclusive = @(, @('url', 'test'))
|
||||
}
|
||||
|
||||
$testModule = [Ansible.Basic.AnsibleModule]::Create(@(), $spec, @(Get-AnsibleWebRequestSpec))
|
||||
|
@ -430,10 +436,10 @@ $tests = [Ordered]@{
|
|||
$actual = Invoke-WithWebRequest -Module $testModule -Request $r -Script {
|
||||
Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
|
||||
|
||||
$Response.ResponseUri | Assert-Equals -Expected "https://$httpbin_host/get"
|
||||
$Response.ResponseUri | Assert-Equal -Expected "https://$httpbin_host/get"
|
||||
Convert-StreamToString -Stream $Stream
|
||||
} | ConvertFrom-Json
|
||||
$actual.headers.'User-Agent' | Assert-Equals -Expected 'actual-agent'
|
||||
$actual.headers.'User-Agent' | Assert-Equal -Expected 'actual-agent'
|
||||
}
|
||||
|
||||
'Web request with default proxy' = {
|
||||
|
@ -442,7 +448,7 @@ $tests = [Ordered]@{
|
|||
}
|
||||
$r = Get-AnsibleWebRequest @params
|
||||
|
||||
$null -ne $r.Proxy | Assert-Equals -Expected $true
|
||||
$null -ne $r.Proxy | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
'Web request with no proxy' = {
|
||||
|
@ -452,7 +458,7 @@ $tests = [Ordered]@{
|
|||
}
|
||||
$r = Get-AnsibleWebRequest @params
|
||||
|
||||
$null -eq $r.Proxy | Assert-Equals -Expected $true
|
||||
$null -eq $r.Proxy | Assert-Equal -Expected $true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,143 +5,82 @@
|
|||
|
||||
$module = [Ansible.Basic.AnsibleModule]::Create($args, @{})
|
||||
|
||||
Function Assert-Equals {
|
||||
Function Assert-Equal {
|
||||
param(
|
||||
[Parameter(Mandatory=$true, ValueFromPipeline=$true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory=$true, Position=0)][AllowNull()]$Expected
|
||||
[Parameter(Mandatory = $true, ValueFromPipeline = $true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory = $true, Position = 0)][AllowNull()]$Expected
|
||||
)
|
||||
|
||||
$matched = $false
|
||||
if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array]) {
|
||||
$Actual.Count | Assert-Equals -Expected $Expected.Count
|
||||
for ($i = 0; $i -lt $Actual.Count; $i++) {
|
||||
$actual_value = $Actual[$i]
|
||||
$expected_value = $Expected[$i]
|
||||
Assert-Equals -Actual $actual_value -Expected $expected_value
|
||||
process {
|
||||
$matched = $false
|
||||
if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array]) {
|
||||
$Actual.Count | Assert-Equal -Expected $Expected.Count
|
||||
for ($i = 0; $i -lt $Actual.Count; $i++) {
|
||||
$actual_value = $Actual[$i]
|
||||
$expected_value = $Expected[$i]
|
||||
Assert-Equal -Actual $actual_value -Expected $expected_value
|
||||
}
|
||||
$matched = $true
|
||||
}
|
||||
$matched = $true
|
||||
} else {
|
||||
$matched = $Actual -ceq $Expected
|
||||
}
|
||||
|
||||
if (-not $matched) {
|
||||
if ($Actual -is [PSObject]) {
|
||||
$Actual = $Actual.ToString()
|
||||
else {
|
||||
$matched = $Actual -ceq $Expected
|
||||
}
|
||||
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.test = $test
|
||||
$module.Result.actual = $Actual
|
||||
$module.Result.expected = $Expected
|
||||
$module.Result.line = $call_stack.ScriptLineNumber
|
||||
$module.Result.method = $call_stack.Position.Text
|
||||
$module.FailJson("AssertionError: actual != expected")
|
||||
if (-not $matched) {
|
||||
if ($Actual -is [PSObject]) {
|
||||
$Actual = $Actual.ToString()
|
||||
}
|
||||
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.test = $test
|
||||
$module.Result.actual = $Actual
|
||||
$module.Result.expected = $Expected
|
||||
$module.Result.line = $call_stack.ScriptLineNumber
|
||||
$module.Result.method = $call_stack.Position.Text
|
||||
$module.FailJson("AssertionError: actual != expected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Function Assert-DictionaryEquals {
|
||||
Function Assert-DictionaryEqual {
|
||||
param(
|
||||
[Parameter(Mandatory=$true, ValueFromPipeline=$true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory=$true, Position=0)][AllowNull()]$Expected
|
||||
[Parameter(Mandatory = $true, ValueFromPipeline = $true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory = $true, Position = 0)][AllowNull()]$Expected
|
||||
)
|
||||
$actual_keys = $Actual.Keys
|
||||
$expected_keys = $Expected.Keys
|
||||
|
||||
$actual_keys.Count | Assert-Equals -Expected $expected_keys.Count
|
||||
foreach ($actual_entry in $Actual.GetEnumerator()) {
|
||||
$actual_key = $actual_entry.Key
|
||||
($actual_key -cin $expected_keys) | Assert-Equals -Expected $true
|
||||
$actual_value = $actual_entry.Value
|
||||
$expected_value = $Expected.$actual_key
|
||||
process {
|
||||
$actual_keys = $Actual.Keys
|
||||
$expected_keys = $Expected.Keys
|
||||
|
||||
if ($actual_value -is [System.Collections.IDictionary]) {
|
||||
$actual_value | Assert-DictionaryEquals -Expected $expected_value
|
||||
} elseif ($actual_value -is [System.Collections.ArrayList]) {
|
||||
for ($i = 0; $i -lt $actual_value.Count; $i++) {
|
||||
$actual_entry = $actual_value[$i]
|
||||
$expected_entry = $expected_value[$i]
|
||||
if ($actual_entry -is [System.Collections.IDictionary]) {
|
||||
$actual_entry | Assert-DictionaryEquals -Expected $expected_entry
|
||||
} else {
|
||||
Assert-Equals -Actual $actual_entry -Expected $expected_entry
|
||||
$actual_keys.Count | Assert-Equal -Expected $expected_keys.Count
|
||||
foreach ($actual_entry in $Actual.GetEnumerator()) {
|
||||
$actual_key = $actual_entry.Key
|
||||
($actual_key -cin $expected_keys) | Assert-Equal -Expected $true
|
||||
$actual_value = $actual_entry.Value
|
||||
$expected_value = $Expected.$actual_key
|
||||
|
||||
if ($actual_value -is [System.Collections.IDictionary]) {
|
||||
$actual_value | Assert-DictionaryEqual -Expected $expected_value
|
||||
}
|
||||
elseif ($actual_value -is [System.Collections.ArrayList]) {
|
||||
for ($i = 0; $i -lt $actual_value.Count; $i++) {
|
||||
$actual_entry = $actual_value[$i]
|
||||
$expected_entry = $expected_value[$i]
|
||||
if ($actual_entry -is [System.Collections.IDictionary]) {
|
||||
$actual_entry | Assert-DictionaryEqual -Expected $expected_entry
|
||||
}
|
||||
else {
|
||||
Assert-Equal -Actual $actual_entry -Expected $expected_entry
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Assert-Equals -Actual $actual_value -Expected $expected_value
|
||||
}
|
||||
}
|
||||
foreach ($expected_key in $expected_keys) {
|
||||
($expected_key -cin $actual_keys) | Assert-Equals -Expected $true
|
||||
}
|
||||
}
|
||||
|
||||
Function Assert-Equals {
|
||||
param(
|
||||
[Parameter(Mandatory=$true, ValueFromPipeline=$true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory=$true, Position=0)][AllowNull()]$Expected
|
||||
)
|
||||
|
||||
$matched = $false
|
||||
if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array]) {
|
||||
$Actual.Count | Assert-Equals -Expected $Expected.Count
|
||||
for ($i = 0; $i -lt $Actual.Count; $i++) {
|
||||
$actual_value = $Actual[$i]
|
||||
$expected_value = $Expected[$i]
|
||||
Assert-Equals -Actual $actual_value -Expected $expected_value
|
||||
}
|
||||
$matched = $true
|
||||
} else {
|
||||
$matched = $Actual -ceq $Expected
|
||||
}
|
||||
|
||||
if (-not $matched) {
|
||||
if ($Actual -is [PSObject]) {
|
||||
$Actual = $Actual.ToString()
|
||||
}
|
||||
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.test = $test
|
||||
$module.Result.actual = $Actual
|
||||
$module.Result.expected = $Expected
|
||||
$module.Result.line = $call_stack.ScriptLineNumber
|
||||
$module.Result.method = $call_stack.Position.Text
|
||||
$module.FailJson("AssertionError: actual != expected")
|
||||
}
|
||||
}
|
||||
|
||||
Function Assert-DictionaryEquals {
|
||||
param(
|
||||
[Parameter(Mandatory=$true, ValueFromPipeline=$true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory=$true, Position=0)][AllowNull()]$Expected
|
||||
)
|
||||
$actual_keys = $Actual.Keys
|
||||
$expected_keys = $Expected.Keys
|
||||
|
||||
$actual_keys.Count | Assert-Equals -Expected $expected_keys.Count
|
||||
foreach ($actual_entry in $Actual.GetEnumerator()) {
|
||||
$actual_key = $actual_entry.Key
|
||||
($actual_key -cin $expected_keys) | Assert-Equals -Expected $true
|
||||
$actual_value = $actual_entry.Value
|
||||
$expected_value = $Expected.$actual_key
|
||||
|
||||
if ($actual_value -is [System.Collections.IDictionary]) {
|
||||
$actual_value | Assert-DictionaryEquals -Expected $expected_value
|
||||
} elseif ($actual_value -is [System.Collections.ArrayList]) {
|
||||
for ($i = 0; $i -lt $actual_value.Count; $i++) {
|
||||
$actual_entry = $actual_value[$i]
|
||||
$expected_entry = $expected_value[$i]
|
||||
if ($actual_entry -is [System.Collections.IDictionary]) {
|
||||
$actual_entry | Assert-DictionaryEquals -Expected $expected_entry
|
||||
} else {
|
||||
Assert-Equals -Actual $actual_entry -Expected $expected_entry
|
||||
}
|
||||
else {
|
||||
Assert-Equal -Actual $actual_value -Expected $expected_value
|
||||
}
|
||||
} else {
|
||||
Assert-Equals -Actual $actual_value -Expected $expected_value
|
||||
}
|
||||
}
|
||||
foreach ($expected_key in $expected_keys) {
|
||||
($expected_key -cin $actual_keys) | Assert-Equals -Expected $true
|
||||
foreach ($expected_key in $expected_keys) {
|
||||
($expected_key -cin $actual_keys) | Assert-Equal -Expected $true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,12 +89,12 @@ $process = [Ansible.Privilege.PrivilegeUtil]::GetCurrentProcess()
|
|||
$tests = @{
|
||||
"Check valid privilege name" = {
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::CheckPrivilegeName("SeTcbPrivilege")
|
||||
$actual | Assert-Equals -Expected $true
|
||||
$actual | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"Check invalid privilege name" = {
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::CheckPrivilegeName("SeFake")
|
||||
$actual | Assert-Equals -Expected $false
|
||||
$actual | Assert-Equal -Expected $false
|
||||
}
|
||||
|
||||
"Disable a privilege" = {
|
||||
|
@ -163,14 +102,14 @@ $tests = @{
|
|||
[Ansible.Privilege.PrivilegeUtil]::EnablePrivilege($process, "SeTimeZonePrivilege") > $null
|
||||
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::DisablePrivilege($process, "SeTimeZonePrivilege")
|
||||
$actual.GetType().Name | Assert-Equals -Expected 'Dictionary`2'
|
||||
$actual.Count | Assert-Equals -Expected 1
|
||||
$actual.SeTimeZonePrivilege | Assert-Equals -Expected $true
|
||||
$actual.GetType().Name | Assert-Equal -Expected 'Dictionary`2'
|
||||
$actual.Count | Assert-Equal -Expected 1
|
||||
$actual.SeTimeZonePrivilege | Assert-Equal -Expected $true
|
||||
|
||||
# Disable again
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::DisablePrivilege($process, "SeTimeZonePrivilege")
|
||||
$actual.GetType().Name | Assert-Equals -Expected 'Dictionary`2'
|
||||
$actual.Count | Assert-Equals -Expected 0
|
||||
$actual.GetType().Name | Assert-Equal -Expected 'Dictionary`2'
|
||||
$actual.Count | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"Enable a privilege" = {
|
||||
|
@ -178,139 +117,154 @@ $tests = @{
|
|||
[Ansible.Privilege.PrivilegeUtil]::DisablePrivilege($process, "SeTimeZonePrivilege") > $null
|
||||
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::EnablePrivilege($process, "SeTimeZonePrivilege")
|
||||
$actual.GetType().Name | Assert-Equals -Expected 'Dictionary`2'
|
||||
$actual.Count | Assert-Equals -Expected 1
|
||||
$actual.SeTimeZonePrivilege | Assert-Equals -Expected $false
|
||||
$actual.GetType().Name | Assert-Equal -Expected 'Dictionary`2'
|
||||
$actual.Count | Assert-Equal -Expected 1
|
||||
$actual.SeTimeZonePrivilege | Assert-Equal -Expected $false
|
||||
|
||||
# Disable again
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::EnablePrivilege($process, "SeTimeZonePrivilege")
|
||||
$actual.GetType().Name | Assert-Equals -Expected 'Dictionary`2'
|
||||
$actual.Count | Assert-Equals -Expected 0
|
||||
$actual.GetType().Name | Assert-Equal -Expected 'Dictionary`2'
|
||||
$actual.Count | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"Disable and revert privileges" = {
|
||||
$current_state = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
|
||||
$previous_state = [Ansible.Privilege.PrivilegeUtil]::DisableAllPrivileges($process)
|
||||
$previous_state.GetType().Name | Assert-Equals -Expected 'Dictionary`2'
|
||||
$previous_state.GetType().Name | Assert-Equal -Expected 'Dictionary`2'
|
||||
foreach ($previous_state_entry in $previous_state.GetEnumerator()) {
|
||||
$previous_state_entry.Value | Assert-Equals -Expected $true
|
||||
$previous_state_entry.Value | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
# Disable again
|
||||
$previous_state2 = [Ansible.Privilege.PrivilegeUtil]::DisableAllPrivileges($process)
|
||||
$previous_state2.Count | Assert-Equals -Expected 0
|
||||
$previous_state2.Count | Assert-Equal -Expected 0
|
||||
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
foreach ($actual_entry in $actual.GetEnumerator()) {
|
||||
$actual_entry.Value -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$actual_entry.Value -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
[Ansible.Privilege.PrivilegeUtil]::SetTokenPrivileges($process, $previous_state) > $null
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
$actual | Assert-DictionaryEquals -Expected $current_state
|
||||
$actual | Assert-DictionaryEqual -Expected $current_state
|
||||
}
|
||||
|
||||
"Remove a privilege" = {
|
||||
[Ansible.Privilege.PrivilegeUtil]::RemovePrivilege($process, "SeUndockPrivilege") > $null
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
$actual.ContainsKey("SeUndockPrivilege") | Assert-Equals -Expected $false
|
||||
$actual.ContainsKey("SeUndockPrivilege") | Assert-Equal -Expected $false
|
||||
}
|
||||
|
||||
"Test Enabler" = {
|
||||
# Disable privilege at the start
|
||||
$new_state = @{
|
||||
SeTimeZonePrivilege = $false
|
||||
SeShutdownPrivilege = $false
|
||||
SeIncreaseWorkingSetPrivilege = $false
|
||||
SeTimeZonePrivilege = $false
|
||||
SeShutdownPrivilege = $false
|
||||
SeIncreaseWorkingSetPrivilege = $false
|
||||
}
|
||||
[Ansible.Privilege.PrivilegeUtil]::SetTokenPrivileges($process, $new_state) > $null
|
||||
$check_state = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
$check_state.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$check_state.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$check_state.SeIncreaseWorkingSetPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$check_state.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
$check_state.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
$check_state.SeIncreaseWorkingSetPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
|
||||
# Check that strict = false won't validate privileges not held but activates the ones we want
|
||||
$enabler = New-Object -TypeName Ansible.Privilege.PrivilegeEnabler -ArgumentList $false, "SeTimeZonePrivilege", "SeShutdownPrivilege", "SeTcbPrivilege"
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
$actual.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeIncreaseWorkingSetPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$actual.ContainsKey("SeTcbPrivilege") | Assert-Equals -Expected $false
|
||||
$actual.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled |
|
||||
Assert-Equal -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled |
|
||||
Assert-Equal -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeIncreaseWorkingSetPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
$actual.ContainsKey("SeTcbPrivilege") | Assert-Equal -Expected $false
|
||||
|
||||
# Now verify a no-op enabler will not rever back to disabled
|
||||
$enabler2 = New-Object -TypeName Ansible.Privilege.PrivilegeEnabler -ArgumentList $false, "SeTimeZonePrivilege", "SeShutdownPrivilege", "SeTcbPrivilege"
|
||||
$enabler2.Dispose()
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
$actual.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled |
|
||||
Assert-Equal -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled |
|
||||
Assert-Equal -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
|
||||
# Verify that when disposing the object the privileges are reverted
|
||||
$enabler.Dispose()
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
$actual.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$actual.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$actual.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
$actual.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"Test Enabler strict" = {
|
||||
# Disable privilege at the start
|
||||
$new_state = @{
|
||||
SeTimeZonePrivilege = $false
|
||||
SeShutdownPrivilege = $false
|
||||
SeIncreaseWorkingSetPrivilege = $false
|
||||
SeTimeZonePrivilege = $false
|
||||
SeShutdownPrivilege = $false
|
||||
SeIncreaseWorkingSetPrivilege = $false
|
||||
}
|
||||
[Ansible.Privilege.PrivilegeUtil]::SetTokenPrivileges($process, $new_state) > $null
|
||||
$check_state = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
$check_state.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$check_state.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$check_state.SeIncreaseWorkingSetPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$check_state.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
$check_state.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
$check_state.SeIncreaseWorkingSetPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
|
||||
# Check that strict = false won't validate privileges not held but activates the ones we want
|
||||
$enabler = New-Object -TypeName Ansible.Privilege.PrivilegeEnabler -ArgumentList $true, "SeTimeZonePrivilege", "SeShutdownPrivilege"
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
$actual.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeIncreaseWorkingSetPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$actual.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled |
|
||||
Assert-Equal -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled |
|
||||
Assert-Equal -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeIncreaseWorkingSetPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
|
||||
# Now verify a no-op enabler will not rever back to disabled
|
||||
$enabler2 = New-Object -TypeName Ansible.Privilege.PrivilegeEnabler -ArgumentList $true, "SeTimeZonePrivilege", "SeShutdownPrivilege"
|
||||
$enabler2.Dispose()
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
$actual.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled |
|
||||
Assert-Equal -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
$actual.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled |
|
||||
Assert-Equal -Expected ([Ansible.Privilege.PrivilegeAttributes]::Enabled)
|
||||
|
||||
# Verify that when disposing the object the privileges are reverted
|
||||
$enabler.Dispose()
|
||||
$actual = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
$actual.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$actual.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$actual.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
$actual.SeShutdownPrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"Test Enabler invalid privilege" = {
|
||||
$failed = $false
|
||||
try {
|
||||
New-Object -TypeName Ansible.Privilege.PrivilegeEnabler -ArgumentList $false, "SeTimeZonePrivilege", "SeFake"
|
||||
} catch {
|
||||
$failed = $true
|
||||
$_.Exception.InnerException.Message | Assert-Equals -Expected "Failed to enable privilege(s) SeTimeZonePrivilege, SeFake (A specified privilege does not exist, Win32ErrorCode 1313)"
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
catch {
|
||||
$failed = $true
|
||||
$expected = "Failed to enable privilege(s) SeTimeZonePrivilege, SeFake (A specified privilege does not exist, Win32ErrorCode 1313)"
|
||||
$_.Exception.InnerException.Message | Assert-Equal -Expected $expected
|
||||
}
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"Test Enabler strict failure" = {
|
||||
# Start disabled
|
||||
[Ansible.Privilege.PrivilegeUtil]::DisablePrivilege($process, "SeTimeZonePrivilege") > $null
|
||||
$check_state = [Ansible.Privilege.PrivilegeUtil]::GetAllPrivilegeInfo($process)
|
||||
$check_state.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equals -Expected 0
|
||||
$check_state.SeTimeZonePrivilege -band [Ansible.Privilege.PrivilegeAttributes]::Enabled | Assert-Equal -Expected 0
|
||||
|
||||
$failed = $false
|
||||
try {
|
||||
New-Object -TypeName Ansible.Privilege.PrivilegeEnabler -ArgumentList $true, "SeTimeZonePrivilege", "SeTcbPrivilege"
|
||||
} catch {
|
||||
$failed = $true
|
||||
$_.Exception.InnerException.Message | Assert-Equals -Expected "Failed to enable privilege(s) SeTimeZonePrivilege, SeTcbPrivilege (Not all privileges or groups referenced are assigned to the caller, Win32ErrorCode 1300)"
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
catch {
|
||||
$failed = $true
|
||||
$expected = -join @(
|
||||
"Failed to enable privilege(s) SeTimeZonePrivilege, SeTcbPrivilege "
|
||||
"(Not all privileges or groups referenced are assigned to the caller, Win32ErrorCode 1300)"
|
||||
)
|
||||
$_.Exception.InnerException.Message | Assert-Equal -Expected $expected
|
||||
}
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,37 +5,40 @@
|
|||
|
||||
$module = [Ansible.Basic.AnsibleModule]::Create($args, @{})
|
||||
|
||||
Function Assert-Equals {
|
||||
Function Assert-Equal {
|
||||
param(
|
||||
[Parameter(Mandatory=$true, ValueFromPipeline=$true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory=$true, Position=0)][AllowNull()]$Expected
|
||||
[Parameter(Mandatory = $true, ValueFromPipeline = $true)][AllowNull()]$Actual,
|
||||
[Parameter(Mandatory = $true, Position = 0)][AllowNull()]$Expected
|
||||
)
|
||||
|
||||
$matched = $false
|
||||
if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array]) {
|
||||
$Actual.Count | Assert-Equals -Expected $Expected.Count
|
||||
for ($i = 0; $i -lt $Actual.Count; $i++) {
|
||||
$actual_value = $Actual[$i]
|
||||
$expected_value = $Expected[$i]
|
||||
Assert-Equals -Actual $actual_value -Expected $expected_value
|
||||
process {
|
||||
$matched = $false
|
||||
if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array]) {
|
||||
$Actual.Count | Assert-Equal -Expected $Expected.Count
|
||||
for ($i = 0; $i -lt $Actual.Count; $i++) {
|
||||
$actual_value = $Actual[$i]
|
||||
$expected_value = $Expected[$i]
|
||||
Assert-Equal -Actual $actual_value -Expected $expected_value
|
||||
}
|
||||
$matched = $true
|
||||
}
|
||||
$matched = $true
|
||||
} else {
|
||||
$matched = $Actual -ceq $Expected
|
||||
}
|
||||
|
||||
if (-not $matched) {
|
||||
if ($Actual -is [PSObject]) {
|
||||
$Actual = $Actual.ToString()
|
||||
else {
|
||||
$matched = $Actual -ceq $Expected
|
||||
}
|
||||
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.test = $test
|
||||
$module.Result.actual = $Actual
|
||||
$module.Result.expected = $Expected
|
||||
$module.Result.line = $call_stack.ScriptLineNumber
|
||||
$module.Result.method = $call_stack.Position.Text
|
||||
$module.FailJson("AssertionError: actual != expected")
|
||||
if (-not $matched) {
|
||||
if ($Actual -is [PSObject]) {
|
||||
$Actual = $Actual.ToString()
|
||||
}
|
||||
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$module.Result.test = $test
|
||||
$module.Result.actual = $Actual
|
||||
$module.Result.expected = $Expected
|
||||
$module.Result.line = $call_stack.ScriptLineNumber
|
||||
$module.Result.method = $call_stack.Position.Text
|
||||
$module.FailJson("AssertionError: actual != expected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,116 +46,118 @@ $tests = @{
|
|||
"ParseCommandLine empty string" = {
|
||||
$expected = @((Get-Process -Id $pid).Path)
|
||||
$actual = [Ansible.Process.ProcessUtil]::ParseCommandLine("")
|
||||
Assert-Equals -Actual $actual -Expected $expected
|
||||
Assert-Equal -Actual $actual -Expected $expected
|
||||
}
|
||||
|
||||
"ParseCommandLine single argument" = {
|
||||
$expected = @("powershell.exe")
|
||||
$actual = [Ansible.Process.ProcessUtil]::ParseCommandLine("powershell.exe")
|
||||
Assert-Equals -Actual $actual -Expected $expected
|
||||
Assert-Equal -Actual $actual -Expected $expected
|
||||
}
|
||||
|
||||
"ParseCommandLine multiple arguments" = {
|
||||
$expected = @("powershell.exe", "-File", "C:\temp\script.ps1")
|
||||
$actual = [Ansible.Process.ProcessUtil]::ParseCommandLine("powershell.exe -File C:\temp\script.ps1")
|
||||
Assert-Equals -Actual $actual -Expected $expected
|
||||
Assert-Equal -Actual $actual -Expected $expected
|
||||
}
|
||||
|
||||
"ParseCommandLine comples arguments" = {
|
||||
$expected = @('abc', 'd', 'ef gh', 'i\j', 'k"l', 'm\n op', 'ADDLOCAL=qr, s', 'tuv\', 'w''x', 'yz')
|
||||
$actual = [Ansible.Process.ProcessUtil]::ParseCommandLine('abc d "ef gh" i\j k\"l m\\"n op" ADDLOCAL="qr, s" tuv\ w''x yz')
|
||||
Assert-Equals -Actual $actual -Expected $expected
|
||||
Assert-Equal -Actual $actual -Expected $expected
|
||||
}
|
||||
|
||||
"SearchPath normal" = {
|
||||
$expected = "$($env:SystemRoot)\System32\WindowsPowerShell\v1.0\powershell.exe"
|
||||
$actual = [Ansible.Process.ProcessUtil]::SearchPath("powershell.exe")
|
||||
$actual | Assert-Equals -Expected $expected
|
||||
$actual | Assert-Equal -Expected $expected
|
||||
}
|
||||
|
||||
"SearchPath missing" = {
|
||||
$failed = $false
|
||||
try {
|
||||
[Ansible.Process.ProcessUtil]::SearchPath("fake.exe")
|
||||
} catch {
|
||||
$failed = $true
|
||||
$_.Exception.InnerException.GetType().FullName | Assert-Equals -Expected "System.IO.FileNotFoundException"
|
||||
$expected = 'Exception calling "SearchPath" with "1" argument(s): "Could not find file ''fake.exe''."'
|
||||
$_.Exception.Message | Assert-Equals -Expected $expected
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
catch {
|
||||
$failed = $true
|
||||
$_.Exception.InnerException.GetType().FullName | Assert-Equal -Expected "System.IO.FileNotFoundException"
|
||||
$expected = 'Exception calling "SearchPath" with "1" argument(s): "Could not find file ''fake.exe''."'
|
||||
$_.Exception.Message | Assert-Equal -Expected $expected
|
||||
}
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"CreateProcess basic" = {
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess("whoami.exe")
|
||||
$actual.GetType().FullName | Assert-Equals -Expected "Ansible.Process.Result"
|
||||
$actual.StandardOut | Assert-Equals -Expected "$(&whoami.exe)`r`n"
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.GetType().FullName | Assert-Equal -Expected "Ansible.Process.Result"
|
||||
$actual.StandardOut | Assert-Equal -Expected "$(&whoami.exe)`r`n"
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcess stderr" = {
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess("powershell.exe [System.Console]::Error.WriteLine('hi')")
|
||||
$actual.StandardOut | Assert-Equals -Expected ""
|
||||
$actual.StandardError | Assert-Equals -Expected "hi`r`n"
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected ""
|
||||
$actual.StandardError | Assert-Equal -Expected "hi`r`n"
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcess exit code" = {
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess("powershell.exe exit 10")
|
||||
$actual.StandardOut | Assert-Equals -Expected ""
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 10
|
||||
$actual.StandardOut | Assert-Equal -Expected ""
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 10
|
||||
}
|
||||
|
||||
"CreateProcess bad executable" = {
|
||||
$failed = $false
|
||||
try {
|
||||
[Ansible.Process.ProcessUtil]::CreateProcess("fake.exe")
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
$failed = $true
|
||||
$_.Exception.InnerException.GetType().FullName | Assert-Equals -Expected "Ansible.Process.Win32Exception"
|
||||
$_.Exception.InnerException.GetType().FullName | Assert-Equal -Expected "Ansible.Process.Win32Exception"
|
||||
$expected = 'Exception calling "CreateProcess" with "1" argument(s): "CreateProcessW() failed '
|
||||
$expected += '(The system cannot find the file specified, Win32ErrorCode 2)"'
|
||||
$_.Exception.Message | Assert-Equals -Expected $expected
|
||||
$_.Exception.Message | Assert-Equal -Expected $expected
|
||||
}
|
||||
$failed | Assert-Equals -Expected $true
|
||||
$failed | Assert-Equal -Expected $true
|
||||
}
|
||||
|
||||
"CreateProcess with unicode" = {
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess("cmd.exe /c echo 💩 café")
|
||||
$actual.StandardOut | Assert-Equals -Expected "💩 café`r`n"
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected "💩 café`r`n"
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, "cmd.exe /c echo 💩 café", $null, $null)
|
||||
$actual.StandardOut | Assert-Equals -Expected "💩 café`r`n"
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected "💩 café`r`n"
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcess without working dir" = {
|
||||
$expected = $pwd.Path + "`r`n"
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe $pwd.Path', $null, $null)
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcess with working dir" = {
|
||||
$expected = "C:\Windows`r`n"
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe $pwd.Path', "C:\Windows", $null)
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcess without environment" = {
|
||||
$expected = "$($env:USERNAME)`r`n"
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe $env:TEST; $env:USERNAME', $null, $null)
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcess with environment" = {
|
||||
|
@ -161,69 +166,70 @@ $tests = @{
|
|||
TEST2 = "Testing 2"
|
||||
}
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'cmd.exe /c set', $null, $env_vars)
|
||||
("TEST=tesTing" -cin $actual.StandardOut.Split("`r`n")) | Assert-Equals -Expected $true
|
||||
("TEST2=Testing 2" -cin $actual.StandardOut.Split("`r`n")) | Assert-Equals -Expected $true
|
||||
("USERNAME=$($env:USERNAME)" -cnotin $actual.StandardOut.Split("`r`n")) | Assert-Equals -Expected $true
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
("TEST=tesTing" -cin $actual.StandardOut.Split("`r`n")) | Assert-Equal -Expected $true
|
||||
("TEST2=Testing 2" -cin $actual.StandardOut.Split("`r`n")) | Assert-Equal -Expected $true
|
||||
("USERNAME=$($env:USERNAME)" -cnotin $actual.StandardOut.Split("`r`n")) | Assert-Equal -Expected $true
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcess with string stdin" = {
|
||||
$expected = "input value`r`n`r`n"
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe [System.Console]::In.ReadToEnd()',
|
||||
$null, $null, "input value")
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcess with string stdin and newline" = {
|
||||
$expected = "input value`r`n`r`n"
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe [System.Console]::In.ReadToEnd()',
|
||||
$null, $null, "input value`r`n")
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcess with byte stdin" = {
|
||||
$expected = "input value`r`n"
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe [System.Console]::In.ReadToEnd()',
|
||||
$null, $null, [System.Text.Encoding]::UTF8.GetBytes("input value"))
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcess with byte stdin and newline" = {
|
||||
$expected = "input value`r`n`r`n"
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe [System.Console]::In.ReadToEnd()',
|
||||
$null, $null, [System.Text.Encoding]::UTF8.GetBytes("input value`r`n"))
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcess with lpApplicationName" = {
|
||||
$expected = "abc`r`n"
|
||||
$full_path = "$($env:SystemRoot)\System32\WindowsPowerShell\v1.0\powershell.exe"
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess($full_path, "Write-Output 'abc'", $null, $null)
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess($full_path, "powershell.exe Write-Output 'abc'", $null, $null)
|
||||
$actual.StandardOut | Assert-Equals -Expected $expected
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected $expected
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
|
||||
"CreateProcess with unicode and us-ascii encoding" = {
|
||||
$poop = [System.Char]::ConvertFromUtf32(0xE05A) # Coverage breaks due to script parsing encoding issues with unicode chars, just use the code point instead
|
||||
# Coverage breaks due to script parsing encoding issues with unicode chars, just use the code point instead
|
||||
$poop = [System.Char]::ConvertFromUtf32(0xE05A)
|
||||
$actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, "cmd.exe /c echo $poop café", $null, $null, '', 'us-ascii')
|
||||
$actual.StandardOut | Assert-Equals -Expected "??? caf??`r`n"
|
||||
$actual.StandardError | Assert-Equals -Expected ""
|
||||
$actual.ExitCode | Assert-Equals -Expected 0
|
||||
$actual.StandardOut | Assert-Equal -Expected "??? caf??`r`n"
|
||||
$actual.StandardError | Assert-Equal -Expected ""
|
||||
$actual.ExitCode | Assert-Equal -Expected 0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,9 +7,9 @@
|
|||
$parsed_args = Parse-Args $args
|
||||
|
||||
$sleep_delay_sec = Get-AnsibleParam -obj $parsed_args -name "sleep_delay_sec" -type "int" -default 0
|
||||
$fail_mode = Get-AnsibleParam -obj $parsed_args -name "fail_mode" -type "str" -default "success" -validateset "success","graceful","exception"
|
||||
$fail_mode = Get-AnsibleParam -obj $parsed_args -name "fail_mode" -type "str" -default "success" -validateset "success", "graceful", "exception"
|
||||
|
||||
If($fail_mode -isnot [array]) {
|
||||
If ($fail_mode -isnot [array]) {
|
||||
$fail_mode = @($fail_mode)
|
||||
}
|
||||
|
||||
|
@ -19,30 +19,29 @@ $result = @{
|
|||
module_tempdir = $PSScriptRoot
|
||||
}
|
||||
|
||||
If($sleep_delay_sec -gt 0) {
|
||||
If ($sleep_delay_sec -gt 0) {
|
||||
Sleep -Seconds $sleep_delay_sec
|
||||
$result["slept_sec"] = $sleep_delay_sec
|
||||
}
|
||||
|
||||
If($fail_mode -contains "leading_junk") {
|
||||
If ($fail_mode -contains "leading_junk") {
|
||||
Write-Output "leading junk before module output"
|
||||
}
|
||||
|
||||
If($fail_mode -contains "graceful") {
|
||||
If ($fail_mode -contains "graceful") {
|
||||
Fail-Json $result "failed gracefully"
|
||||
}
|
||||
|
||||
Try {
|
||||
|
||||
If($fail_mode -contains "exception") {
|
||||
If ($fail_mode -contains "exception") {
|
||||
Throw "failing via exception"
|
||||
}
|
||||
|
||||
Exit-Json $result
|
||||
}
|
||||
Finally
|
||||
{
|
||||
If($fail_mode -contains "trailing_junk") {
|
||||
Finally {
|
||||
If ($fail_mode -contains "trailing_junk") {
|
||||
Write-Output "trailing junk after module output"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,13 @@
|
|||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Function Assert-Equals($actual, $expected) {
|
||||
Function Assert-Equal($actual, $expected) {
|
||||
if ($actual -cne $expected) {
|
||||
$call_stack = (Get-PSCallStack)[1]
|
||||
$error_msg = "AssertionError:`r`nActual: `"$actual`" != Expected: `"$expected`"`r`nLine: $($call_stack.ScriptLineNumber), Method: $($call_stack.Position.Text)"
|
||||
$error_msg = -join @(
|
||||
"AssertionError:`r`nActual: `"$actual`" != Expected: `"$expected`"`r`nLine: "
|
||||
"$($call_stack.ScriptLineNumber), Method: $($call_stack.Position.Text)"
|
||||
)
|
||||
Fail-Json -obj $result -message $error_msg
|
||||
}
|
||||
}
|
||||
|
@ -17,23 +20,23 @@ $result = @{
|
|||
}
|
||||
|
||||
#ConvertFrom-AnsibleJso
|
||||
$input_json = '{"string":"string","float":3.1415926,"dict":{"string":"string","int":1},"list":["entry 1","entry 2"],"null":null,"int":1}'
|
||||
$input_json = '{"string":"string","float":3.1415926,"dict":{"string":"string","int":1},"list":["entry 1","entry 2"],"null":null,"int":1}'
|
||||
$actual = ConvertFrom-AnsibleJson -InputObject $input_json
|
||||
Assert-Equals -actual $actual.GetType() -expected ([Hashtable])
|
||||
Assert-Equals -actual $actual.string.GetType() -expected ([String])
|
||||
Assert-Equals -actual $actual.string -expected "string"
|
||||
Assert-Equals -actual $actual.int.GetType() -expected ([Int32])
|
||||
Assert-Equals -actual $actual.int -expected 1
|
||||
Assert-Equals -actual $actual.null -expected $null
|
||||
Assert-Equals -actual $actual.float.GetType() -expected ([Decimal])
|
||||
Assert-Equals -actual $actual.float -expected 3.1415926
|
||||
Assert-Equals -actual $actual.list.GetType() -expected ([Object[]])
|
||||
Assert-Equals -actual $actual.list.Count -expected 2
|
||||
Assert-Equals -actual $actual.list[0] -expected "entry 1"
|
||||
Assert-Equals -actual $actual.list[1] -expected "entry 2"
|
||||
Assert-Equals -actual $actual.GetType() -expected ([Hashtable])
|
||||
Assert-Equals -actual $actual.dict.string -expected "string"
|
||||
Assert-Equals -actual $actual.dict.int -expected 1
|
||||
Assert-Equal -actual $actual.GetType() -expected ([Hashtable])
|
||||
Assert-Equal -actual $actual.string.GetType() -expected ([String])
|
||||
Assert-Equal -actual $actual.string -expected "string"
|
||||
Assert-Equal -actual $actual.int.GetType() -expected ([Int32])
|
||||
Assert-Equal -actual $actual.int -expected 1
|
||||
Assert-Equal -actual $actual.null -expected $null
|
||||
Assert-Equal -actual $actual.float.GetType() -expected ([Decimal])
|
||||
Assert-Equal -actual $actual.float -expected 3.1415926
|
||||
Assert-Equal -actual $actual.list.GetType() -expected ([Object[]])
|
||||
Assert-Equal -actual $actual.list.Count -expected 2
|
||||
Assert-Equal -actual $actual.list[0] -expected "entry 1"
|
||||
Assert-Equal -actual $actual.list[1] -expected "entry 2"
|
||||
Assert-Equal -actual $actual.GetType() -expected ([Hashtable])
|
||||
Assert-Equal -actual $actual.dict.string -expected "string"
|
||||
Assert-Equal -actual $actual.dict.int -expected 1
|
||||
|
||||
$result.msg = "good"
|
||||
Exit-Json -obj $result
|
||||
|
|
|
@ -31,24 +31,32 @@ Function Test-ThrowException {
|
|||
|
||||
if ($data -eq "normal") {
|
||||
Exit-Json -obj $result
|
||||
} elseif ($data -eq "fail") {
|
||||
}
|
||||
elseif ($data -eq "fail") {
|
||||
Fail-Json -obj $result -message "fail message"
|
||||
} elseif ($data -eq "throw") {
|
||||
}
|
||||
elseif ($data -eq "throw") {
|
||||
throw [ArgumentException]"module is thrown"
|
||||
} elseif ($data -eq "error") {
|
||||
}
|
||||
elseif ($data -eq "error") {
|
||||
Write-Error -Message $data
|
||||
} elseif ($data -eq "cmdlet_error") {
|
||||
}
|
||||
elseif ($data -eq "cmdlet_error") {
|
||||
Get-Item -Path "fake:\path"
|
||||
} elseif ($data -eq "dotnet_exception") {
|
||||
}
|
||||
elseif ($data -eq "dotnet_exception") {
|
||||
[System.IO.Path]::GetFullPath($null)
|
||||
} elseif ($data -eq "function_throw") {
|
||||
}
|
||||
elseif ($data -eq "function_throw") {
|
||||
Test-ThrowException
|
||||
} elseif ($data -eq "proc_exit_fine") {
|
||||
}
|
||||
elseif ($data -eq "proc_exit_fine") {
|
||||
# verifies that if no error was actually fired and we have an output, we
|
||||
# don't use the RC to validate if the module failed
|
||||
&cmd.exe /c exit 2
|
||||
Exit-Json -obj $result
|
||||
} elseif ($data -eq "proc_exit_fail") {
|
||||
}
|
||||
elseif ($data -eq "proc_exit_fail") {
|
||||
&cmd.exe /c exit 2
|
||||
Fail-Json -obj $result -message "proc_exit_fail"
|
||||
}
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
#Requires -Module Ansible.ModuleUtils.Legacy
|
||||
|
||||
Exit-Json @{ data="success" }
|
||||
Exit-Json @{ data = "success" }
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
|
||||
#Requires -Module Ansible.ModuleUtils.Legacy
|
||||
|
||||
Exit-Json @{ data="success" }
|
||||
Exit-Json @{ data = "success" }
|
||||
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
Exit-Json @{ data="success" }
|
||||
Exit-Json @{ data = "success" }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!powershell
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
Exit-Json @{ data="success" }
|
||||
Exit-Json @{ data = "success" }
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
# this should fail
|
||||
#Requires -Module Ansible.ModuleUtils.BogusModule
|
||||
|
||||
Exit-Json @{ data="success" }
|
||||
Exit-Json @{ data = "success" }
|
||||
|
|
|
@ -6,4 +6,4 @@
|
|||
|
||||
$o = CustomFunction
|
||||
|
||||
Exit-Json @{data=$o}
|
||||
Exit-Json @{data = $o }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Param(
|
||||
[bool]$boolvariable
|
||||
[bool]$boolvariable
|
||||
)
|
||||
|
||||
Write-Output $boolvariable.GetType().FullName
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# Test script to create a file.
|
||||
|
||||
echo $null > $args[0]
|
||||
Write-Output $null > $args[0]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# Test script to make sure the Ansible script module works when arguments are
|
||||
# passed to the script.
|
||||
|
||||
foreach ($i in $args)
|
||||
{
|
||||
foreach ($i in $args) {
|
||||
Write-Host $i;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# Test script to make sure we handle non-zero exit codes.
|
||||
|
||||
trap
|
||||
{
|
||||
trap {
|
||||
Write-Error -ErrorRecord $_
|
||||
exit 1;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ A list of hosts entries, delimited by '|'.
|
|||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=0)][String]$Hosts
|
||||
[Parameter(Mandatory = $true, Position = 0)][String]$Hosts
|
||||
)
|
||||
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
|
|
|
@ -8,7 +8,7 @@ A list of hosts entries, delimited by '|'.
|
|||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=0)][String]$Hosts
|
||||
[Parameter(Mandatory = $true, Position = 0)][String]$Hosts
|
||||
)
|
||||
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
|
@ -26,7 +26,8 @@ $new_lines = [System.Collections.ArrayList]@()
|
|||
foreach ($host_line in $hosts_file_lines) {
|
||||
if ($host_line -in $hosts_entries) {
|
||||
$changed = $true
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$new_lines += $host_line
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ param (
|
|||
$IsContainer
|
||||
)
|
||||
|
||||
#Requires -Version 6
|
||||
#Requires -Version 7
|
||||
|
||||
Set-StrictMode -Version 2.0
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
@ -12,11 +12,11 @@ $ProgressPreference = 'SilentlyContinue'
|
|||
Function Install-PSModule {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[Parameter(Mandatory = $true)]
|
||||
[String]
|
||||
$Name,
|
||||
|
||||
[Parameter(Mandatory=$true)]
|
||||
[Parameter(Mandatory = $true)]
|
||||
[Version]
|
||||
$RequiredVersion
|
||||
)
|
||||
|
@ -25,11 +25,11 @@ Function Install-PSModule {
|
|||
$installedModule = Get-Module -Name $Name -ListAvailable | Where-Object Version -eq $RequiredVersion
|
||||
if (-not $installedModule) {
|
||||
Install-Module -Name $Name -RequiredVersion $RequiredVersion -Scope CurrentUser
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
|
||||
Install-PSModule -Name PSScriptAnalyzer -RequiredVersion 1.18.0
|
||||
Install-PSModule -Name PSScriptAnalyzer -RequiredVersion 1.20.0
|
||||
|
||||
if ($IsContainer) {
|
||||
# PSScriptAnalyzer contain lots of json files for the UseCompatibleCommands check. We don't use this rule so by
|
||||
|
|
|
@ -4,12 +4,6 @@
|
|||
$ErrorActionPreference = "Stop"
|
||||
$WarningPreference = "Stop"
|
||||
|
||||
# Until https://github.com/PowerShell/PSScriptAnalyzer/issues/1217 is fixed we need to import Pester if it's
|
||||
# available.
|
||||
if (Get-Module -Name Pester -ListAvailable -ErrorAction SilentlyContinue) {
|
||||
Import-Module -Name Pester
|
||||
}
|
||||
|
||||
$LiteralPathRule = Import-Module -Name PSSA-PSCustomUseLiteralPath -PassThru
|
||||
$LiteralPathRulePath = Join-Path -Path $LiteralPathRule.ModuleBase -ChildPath $LiteralPathRule.RootModule
|
||||
|
||||
|
@ -19,22 +13,24 @@ $PSSAParams = @{
|
|||
Setting = (Join-Path -Path $PSScriptRoot -ChildPath "settings.psd1")
|
||||
}
|
||||
|
||||
$Results = @(ForEach ($Path in $Args) {
|
||||
$Retries = 3
|
||||
$Results = @(
|
||||
ForEach ($Path in $Args) {
|
||||
$Retries = 3
|
||||
|
||||
Do {
|
||||
Try {
|
||||
Invoke-ScriptAnalyzer -Path $Path @PSSAParams 3> $null
|
||||
$Retries = 0
|
||||
}
|
||||
Catch {
|
||||
If (--$Retries -le 0) {
|
||||
Throw
|
||||
Do {
|
||||
Try {
|
||||
Invoke-ScriptAnalyzer -Path $Path @PSSAParams 3> $null
|
||||
$Retries = 0
|
||||
}
|
||||
Catch {
|
||||
If (--$Retries -le 0) {
|
||||
Throw
|
||||
}
|
||||
}
|
||||
}
|
||||
Until ($Retries -le 0)
|
||||
}
|
||||
Until ($Retries -le 0)
|
||||
})
|
||||
)
|
||||
|
||||
# Since pwsh 7.1 results that exceed depth will produce a warning which fails the process.
|
||||
# Ignore warnings only for this step.
|
||||
|
|
|
@ -1,5 +1,41 @@
|
|||
@{
|
||||
ExcludeRules=@(
|
||||
Rules = @{
|
||||
PSAvoidLongLines = @{
|
||||
Enable = $true
|
||||
MaximumLineLength = 160
|
||||
}
|
||||
PSPlaceOpenBrace = @{
|
||||
Enable = $true
|
||||
OnSameLine = $true
|
||||
IgnoreOneLineBlock = $true
|
||||
NewLineAfter = $true
|
||||
}
|
||||
PSPlaceCloseBrace = @{
|
||||
Enable = $true
|
||||
IgnoreOneLineBlock = $true
|
||||
NewLineAfter = $true
|
||||
NoEmptyLineBefore = $false
|
||||
}
|
||||
PSUseConsistentIndentation = @{
|
||||
Enable = $true
|
||||
IndentationSize = 4
|
||||
PipelineIndentation = 'IncreaseIndentationForFirstPipeline'
|
||||
Kind = 'space'
|
||||
}
|
||||
PSUseConsistentWhitespace = @{
|
||||
Enable = $true
|
||||
CheckInnerBrace = $true
|
||||
CheckOpenBrace = $true
|
||||
CheckOpenParen = $true
|
||||
CheckOperator = $true
|
||||
CheckPipe = $true
|
||||
CheckPipeForRedundantWhitespace = $false
|
||||
CheckSeparator = $true
|
||||
CheckParameter = $false
|
||||
IgnoreAssignmentOperatorInsideHashTable = $false
|
||||
}
|
||||
}
|
||||
ExcludeRules = @(
|
||||
'PSUseOutputTypeCorrectly',
|
||||
'PSUseShouldProcessForStateChangingFunctions',
|
||||
# We send strings as plaintext so will always come across the 3 issues
|
||||
|
@ -8,6 +44,9 @@
|
|||
'PSAvoidUsingUserNameAndPassWordParams',
|
||||
# We send the module as a base64 encoded string and a BOM will cause
|
||||
# issues here
|
||||
'PSUseBOMForUnicodeEncodedFile'
|
||||
'PSUseBOMForUnicodeEncodedFile',
|
||||
# Too many false positives, there are many cases where shared utils
|
||||
# invoke user defined code but not all parameters are used.
|
||||
'PSReviewUnusedParameter'
|
||||
)
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ Function Resolve-CircularReference {
|
|||
#>
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[Parameter(Mandatory = $true)]
|
||||
[System.Collections.IDictionary]
|
||||
$Hash
|
||||
)
|
||||
|
@ -23,22 +23,26 @@ Function Resolve-CircularReference {
|
|||
$value = $Hash[$key]
|
||||
if ($value -is [System.Collections.IDictionary]) {
|
||||
Resolve-CircularReference -Hash $value
|
||||
} elseif ($value -is [Array] -or $value -is [System.Collections.IList]) {
|
||||
}
|
||||
elseif ($value -is [Array] -or $value -is [System.Collections.IList]) {
|
||||
$values = @(foreach ($v in $value) {
|
||||
if ($v -is [System.Collections.IDictionary]) {
|
||||
Resolve-CircularReference -Hash $v
|
||||
}
|
||||
,$v
|
||||
})
|
||||
if ($v -is [System.Collections.IDictionary]) {
|
||||
Resolve-CircularReference -Hash $v
|
||||
}
|
||||
, $v
|
||||
})
|
||||
$Hash[$key] = $values
|
||||
} elseif ($value -is [DateTime]) {
|
||||
}
|
||||
elseif ($value -is [DateTime]) {
|
||||
$Hash[$key] = $value.ToString("yyyy-MM-dd")
|
||||
} elseif ($value -is [delegate]) {
|
||||
}
|
||||
elseif ($value -is [delegate]) {
|
||||
# Type can be set to a delegate function which defines it's own type. For the documentation we just
|
||||
# reflection that as raw
|
||||
if ($key -eq 'type') {
|
||||
$Hash[$key] = 'raw'
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$Hash[$key] = $value.ToString() # Shouldn't ever happen but just in case.
|
||||
}
|
||||
}
|
||||
|
@ -81,9 +85,9 @@ if ($manifest.Contains('ps_utils')) {
|
|||
|
||||
$util_sb = [ScriptBlock]::Create((Get-Content -LiteralPath $util_path -Raw))
|
||||
$powershell.AddCommand('New-Module').AddParameters(@{
|
||||
Name = $util_name
|
||||
ScriptBlock = $util_sb
|
||||
}) > $null
|
||||
Name = $util_name
|
||||
ScriptBlock = $util_sb
|
||||
}) > $null
|
||||
$powershell.AddCommand('Import-Module').AddParameter('WarningAction', 'SilentlyContinue') > $null
|
||||
$powershell.AddCommand('Out-Null').AddStatement() > $null
|
||||
|
||||
|
|
|
@ -9,30 +9,32 @@ param (
|
|||
$Path
|
||||
)
|
||||
|
||||
$stubInfo = @(foreach ($sourcePath in $Path) {
|
||||
# Default is to just no lines for missing files
|
||||
[Collections.Generic.HashSet[int]]$lines = @()
|
||||
$stubInfo = @(
|
||||
foreach ($sourcePath in $Path) {
|
||||
# Default is to just no lines for missing files
|
||||
[Collections.Generic.HashSet[int]]$lines = @()
|
||||
|
||||
if (Test-Path -LiteralPath $sourcePath) {
|
||||
$code = [ScriptBlock]::Create([IO.File]::ReadAllText($sourcePath))
|
||||
if (Test-Path -LiteralPath $sourcePath) {
|
||||
$code = [ScriptBlock]::Create([IO.File]::ReadAllText($sourcePath))
|
||||
|
||||
# We set our breakpoints with this predicate so our stubs should match
|
||||
# that logic.
|
||||
$predicate = {
|
||||
$args[0] -is [System.Management.Automation.Language.CommandBaseAst]
|
||||
# We set our breakpoints with this predicate so our stubs should match
|
||||
# that logic.
|
||||
$predicate = {
|
||||
$args[0] -is [System.Management.Automation.Language.CommandBaseAst]
|
||||
}
|
||||
$cmds = $code.Ast.FindAll($predicate, $true)
|
||||
|
||||
# We only care about unique lines not multiple commands on 1 line.
|
||||
$lines = @(foreach ($cmd in $cmds) {
|
||||
$cmd.Extent.StartLineNumber
|
||||
})
|
||||
}
|
||||
$cmds = $code.Ast.FindAll($predicate, $true)
|
||||
|
||||
# We only care about unique lines not multiple commands on 1 line.
|
||||
$lines = @(foreach ($cmd in $cmds) {
|
||||
$cmd.Extent.StartLineNumber
|
||||
})
|
||||
[PSCustomObject]@{
|
||||
Path = $sourcePath
|
||||
Lines = $lines
|
||||
}
|
||||
}
|
||||
|
||||
[PSCustomObject]@{
|
||||
Path = $sourcePath
|
||||
Lines = $lines
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
ConvertTo-Json -InputObject $stubInfo -Depth 2 -Compress
|
||||
|
|
|
@ -66,28 +66,24 @@ Param (
|
|||
[switch]$EnableCredSSP
|
||||
)
|
||||
|
||||
Function Write-Log
|
||||
{
|
||||
Function Write-ProgressLog {
|
||||
$Message = $args[0]
|
||||
Write-EventLog -LogName Application -Source $EventSource -EntryType Information -EventId 1 -Message $Message
|
||||
}
|
||||
|
||||
Function Write-VerboseLog
|
||||
{
|
||||
Function Write-VerboseLog {
|
||||
$Message = $args[0]
|
||||
Write-Verbose $Message
|
||||
Write-Log $Message
|
||||
Write-ProgressLog $Message
|
||||
}
|
||||
|
||||
Function Write-HostLog
|
||||
{
|
||||
Function Write-HostLog {
|
||||
$Message = $args[0]
|
||||
Write-Output $Message
|
||||
Write-Log $Message
|
||||
Write-ProgressLog $Message
|
||||
}
|
||||
|
||||
Function New-LegacySelfSignedCert
|
||||
{
|
||||
Function New-LegacySelfSignedCert {
|
||||
Param (
|
||||
[string]$SubjectName,
|
||||
[int]$ValidDays = 1095
|
||||
|
@ -125,14 +121,13 @@ Function New-LegacySelfSignedCert
|
|||
$SigOID = New-Object -ComObject X509Enrollment.CObjectId
|
||||
$SigOID.InitializeFromValue(([Security.Cryptography.Oid]$SignatureAlgorithm).Value)
|
||||
|
||||
[string[]] $AlternativeName += $hostnonFQDN
|
||||
[string[]] $AlternativeName += $hostnonFQDN
|
||||
$AlternativeName += $hostFQDN
|
||||
$IAlternativeNames = New-Object -ComObject X509Enrollment.CAlternativeNames
|
||||
|
||||
foreach ($AN in $AlternativeName)
|
||||
{
|
||||
foreach ($AN in $AlternativeName) {
|
||||
$AltName = New-Object -ComObject X509Enrollment.CAlternativeName
|
||||
$AltName.InitializeFromString(0x3,$AN)
|
||||
$AltName.InitializeFromString(0x3, $AN)
|
||||
$IAlternativeNames.Add($AltName)
|
||||
}
|
||||
|
||||
|
@ -162,15 +157,14 @@ Function New-LegacySelfSignedCert
|
|||
return $parsed_cert.Thumbprint
|
||||
}
|
||||
|
||||
Function Enable-GlobalHttpFirewallAccess
|
||||
{
|
||||
Function Enable-GlobalHttpFirewallAccess {
|
||||
Write-Verbose "Forcing global HTTP firewall access"
|
||||
# this is a fairly naive implementation; could be more sophisticated about rule matching/collapsing
|
||||
$fw = New-Object -ComObject HNetCfg.FWPolicy2
|
||||
|
||||
# try to find/enable the default rule first
|
||||
$add_rule = $false
|
||||
$matching_rules = $fw.Rules | Where-Object { $_.Name -eq "Windows Remote Management (HTTP-In)" }
|
||||
$matching_rules = $fw.Rules | Where-Object { $_.Name -eq "Windows Remote Management (HTTP-In)" }
|
||||
$rule = $null
|
||||
If ($matching_rules) {
|
||||
If ($matching_rules -isnot [Array]) {
|
||||
|
@ -217,80 +211,71 @@ Function Enable-GlobalHttpFirewallAccess
|
|||
}
|
||||
|
||||
# Setup error handling.
|
||||
Trap
|
||||
{
|
||||
Trap {
|
||||
$_
|
||||
Exit 1
|
||||
}
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Get the ID and security principal of the current user account
|
||||
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
|
||||
$myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$myWindowsPrincipal = new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
|
||||
|
||||
# Get the security principal for the Administrator role
|
||||
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
|
||||
$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator
|
||||
|
||||
# Check to see if we are currently running "as Administrator"
|
||||
if (-Not $myWindowsPrincipal.IsInRole($adminRole))
|
||||
{
|
||||
if (-Not $myWindowsPrincipal.IsInRole($adminRole)) {
|
||||
Write-Output "ERROR: You need elevated Administrator privileges in order to run this script."
|
||||
Write-Output " Start Windows PowerShell by using the Run as Administrator option."
|
||||
Exit 2
|
||||
}
|
||||
|
||||
$EventSource = $MyInvocation.MyCommand.Name
|
||||
If (-Not $EventSource)
|
||||
{
|
||||
If (-Not $EventSource) {
|
||||
$EventSource = "Powershell CLI"
|
||||
}
|
||||
|
||||
If ([System.Diagnostics.EventLog]::Exists('Application') -eq $False -or [System.Diagnostics.EventLog]::SourceExists($EventSource) -eq $False)
|
||||
{
|
||||
If ([System.Diagnostics.EventLog]::Exists('Application') -eq $False -or [System.Diagnostics.EventLog]::SourceExists($EventSource) -eq $False) {
|
||||
New-EventLog -LogName Application -Source $EventSource
|
||||
}
|
||||
|
||||
# Detect PowerShell version.
|
||||
If ($PSVersionTable.PSVersion.Major -lt 3)
|
||||
{
|
||||
Write-Log "PowerShell version 3 or higher is required."
|
||||
If ($PSVersionTable.PSVersion.Major -lt 3) {
|
||||
Write-ProgressLog "PowerShell version 3 or higher is required."
|
||||
Throw "PowerShell version 3 or higher is required."
|
||||
}
|
||||
|
||||
# Find and start the WinRM service.
|
||||
Write-Verbose "Verifying WinRM service."
|
||||
If (!(Get-Service "WinRM"))
|
||||
{
|
||||
Write-Log "Unable to find the WinRM service."
|
||||
If (!(Get-Service "WinRM")) {
|
||||
Write-ProgressLog "Unable to find the WinRM service."
|
||||
Throw "Unable to find the WinRM service."
|
||||
}
|
||||
ElseIf ((Get-Service "WinRM").Status -ne "Running")
|
||||
{
|
||||
ElseIf ((Get-Service "WinRM").Status -ne "Running") {
|
||||
Write-Verbose "Setting WinRM service to start automatically on boot."
|
||||
Set-Service -Name "WinRM" -StartupType Automatic
|
||||
Write-Log "Set WinRM service to start automatically on boot."
|
||||
Write-ProgressLog "Set WinRM service to start automatically on boot."
|
||||
Write-Verbose "Starting WinRM service."
|
||||
Start-Service -Name "WinRM" -ErrorAction Stop
|
||||
Write-Log "Started WinRM service."
|
||||
Write-ProgressLog "Started WinRM service."
|
||||
|
||||
}
|
||||
|
||||
# WinRM should be running; check that we have a PS session config.
|
||||
If (!(Get-PSSessionConfiguration -Verbose:$false) -or (!(Get-ChildItem WSMan:\localhost\Listener)))
|
||||
{
|
||||
If ($SkipNetworkProfileCheck) {
|
||||
Write-Verbose "Enabling PS Remoting without checking Network profile."
|
||||
Enable-PSRemoting -SkipNetworkProfileCheck -Force -ErrorAction Stop
|
||||
Write-Log "Enabled PS Remoting without checking Network profile."
|
||||
}
|
||||
Else {
|
||||
Write-Verbose "Enabling PS Remoting."
|
||||
Enable-PSRemoting -Force -ErrorAction Stop
|
||||
Write-Log "Enabled PS Remoting."
|
||||
}
|
||||
If (!(Get-PSSessionConfiguration -Verbose:$false) -or (!(Get-ChildItem WSMan:\localhost\Listener))) {
|
||||
If ($SkipNetworkProfileCheck) {
|
||||
Write-Verbose "Enabling PS Remoting without checking Network profile."
|
||||
Enable-PSRemoting -SkipNetworkProfileCheck -Force -ErrorAction Stop
|
||||
Write-ProgressLog "Enabled PS Remoting without checking Network profile."
|
||||
}
|
||||
Else {
|
||||
Write-Verbose "Enabling PS Remoting."
|
||||
Enable-PSRemoting -Force -ErrorAction Stop
|
||||
Write-ProgressLog "Enabled PS Remoting."
|
||||
}
|
||||
}
|
||||
Else
|
||||
{
|
||||
Else {
|
||||
Write-Verbose "PS Remoting is already enabled."
|
||||
}
|
||||
|
||||
|
@ -310,8 +295,7 @@ if ($token_value -ne 1) {
|
|||
|
||||
# Make sure there is a SSL listener.
|
||||
$listeners = Get-ChildItem WSMan:\localhost\Listener
|
||||
If (!($listeners | Where-Object {$_.Keys -like "TRANSPORT=HTTPS"}))
|
||||
{
|
||||
If (!($listeners | Where-Object { $_.Keys -like "TRANSPORT=HTTPS" })) {
|
||||
# We cannot use New-SelfSignedCertificate on 2012R2 and earlier
|
||||
$thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName -ValidDays $CertValidityDays
|
||||
Write-HostLog "Self-signed SSL certificate generated; thumbprint: $thumbprint"
|
||||
|
@ -329,15 +313,13 @@ If (!($listeners | Where-Object {$_.Keys -like "TRANSPORT=HTTPS"}))
|
|||
|
||||
Write-Verbose "Enabling SSL listener."
|
||||
New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset
|
||||
Write-Log "Enabled SSL listener."
|
||||
Write-ProgressLog "Enabled SSL listener."
|
||||
}
|
||||
Else
|
||||
{
|
||||
Else {
|
||||
Write-Verbose "SSL listener is already active."
|
||||
|
||||
# Force a new SSL cert on Listener if the $ForceNewSSLCert
|
||||
If ($ForceNewSSLCert)
|
||||
{
|
||||
If ($ForceNewSSLCert) {
|
||||
|
||||
# We cannot use New-SelfSignedCertificate on 2012R2 and earlier
|
||||
$thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName -ValidDays $CertValidityDays
|
||||
|
@ -361,45 +343,37 @@ Else
|
|||
}
|
||||
|
||||
# Check for basic authentication.
|
||||
$basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object {$_.Name -eq "Basic"}
|
||||
$basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object { $_.Name -eq "Basic" }
|
||||
|
||||
If ($DisableBasicAuth)
|
||||
{
|
||||
If (($basicAuthSetting.Value) -eq $true)
|
||||
{
|
||||
If ($DisableBasicAuth) {
|
||||
If (($basicAuthSetting.Value) -eq $true) {
|
||||
Write-Verbose "Disabling basic auth support."
|
||||
Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $false
|
||||
Write-Log "Disabled basic auth support."
|
||||
Write-ProgressLog "Disabled basic auth support."
|
||||
}
|
||||
Else
|
||||
{
|
||||
Else {
|
||||
Write-Verbose "Basic auth is already disabled."
|
||||
}
|
||||
}
|
||||
Else
|
||||
{
|
||||
If (($basicAuthSetting.Value) -eq $false)
|
||||
{
|
||||
Else {
|
||||
If (($basicAuthSetting.Value) -eq $false) {
|
||||
Write-Verbose "Enabling basic auth support."
|
||||
Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $true
|
||||
Write-Log "Enabled basic auth support."
|
||||
Write-ProgressLog "Enabled basic auth support."
|
||||
}
|
||||
Else
|
||||
{
|
||||
Else {
|
||||
Write-Verbose "Basic auth is already enabled."
|
||||
}
|
||||
}
|
||||
|
||||
# If EnableCredSSP if set to true
|
||||
If ($EnableCredSSP)
|
||||
{
|
||||
If ($EnableCredSSP) {
|
||||
# Check for CredSSP authentication
|
||||
$credsspAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object {$_.Name -eq "CredSSP"}
|
||||
If (($credsspAuthSetting.Value) -eq $false)
|
||||
{
|
||||
$credsspAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object { $_.Name -eq "CredSSP" }
|
||||
If (($credsspAuthSetting.Value) -eq $false) {
|
||||
Write-Verbose "Enabling CredSSP auth support."
|
||||
Enable-WSManCredSSP -role server -Force
|
||||
Write-Log "Enabled CredSSP auth support."
|
||||
Write-ProgressLog "Enabled CredSSP auth support."
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -410,44 +384,37 @@ If ($GlobalHttpFirewallAccess) {
|
|||
# Configure firewall to allow WinRM HTTPS connections.
|
||||
$fwtest1 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS"
|
||||
$fwtest2 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS" profile=any
|
||||
If ($fwtest1.count -lt 5)
|
||||
{
|
||||
If ($fwtest1.count -lt 5) {
|
||||
Write-Verbose "Adding firewall rule to allow WinRM HTTPS."
|
||||
netsh advfirewall firewall add rule profile=any name="Allow WinRM HTTPS" dir=in localport=5986 protocol=TCP action=allow
|
||||
Write-Log "Added firewall rule to allow WinRM HTTPS."
|
||||
Write-ProgressLog "Added firewall rule to allow WinRM HTTPS."
|
||||
}
|
||||
ElseIf (($fwtest1.count -ge 5) -and ($fwtest2.count -lt 5))
|
||||
{
|
||||
ElseIf (($fwtest1.count -ge 5) -and ($fwtest2.count -lt 5)) {
|
||||
Write-Verbose "Updating firewall rule to allow WinRM HTTPS for any profile."
|
||||
netsh advfirewall firewall set rule name="Allow WinRM HTTPS" new profile=any
|
||||
Write-Log "Updated firewall rule to allow WinRM HTTPS for any profile."
|
||||
Write-ProgressLog "Updated firewall rule to allow WinRM HTTPS for any profile."
|
||||
}
|
||||
Else
|
||||
{
|
||||
Else {
|
||||
Write-Verbose "Firewall rule already exists to allow WinRM HTTPS."
|
||||
}
|
||||
|
||||
# Test a remoting connection to localhost, which should work.
|
||||
$httpResult = Invoke-Command -ComputerName "localhost" -ScriptBlock {$env:COMPUTERNAME} -ErrorVariable httpError -ErrorAction SilentlyContinue
|
||||
$httpResult = Invoke-Command -ComputerName "localhost" -ScriptBlock { $using:env:COMPUTERNAME } -ErrorVariable httpError -ErrorAction SilentlyContinue
|
||||
$httpsOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
|
||||
|
||||
$httpsResult = New-PSSession -UseSSL -ComputerName "localhost" -SessionOption $httpsOptions -ErrorVariable httpsError -ErrorAction SilentlyContinue
|
||||
|
||||
If ($httpResult -and $httpsResult)
|
||||
{
|
||||
If ($httpResult -and $httpsResult) {
|
||||
Write-Verbose "HTTP: Enabled | HTTPS: Enabled"
|
||||
}
|
||||
ElseIf ($httpsResult -and !$httpResult)
|
||||
{
|
||||
ElseIf ($httpsResult -and !$httpResult) {
|
||||
Write-Verbose "HTTP: Disabled | HTTPS: Enabled"
|
||||
}
|
||||
ElseIf ($httpResult -and !$httpsResult)
|
||||
{
|
||||
ElseIf ($httpResult -and !$httpsResult) {
|
||||
Write-Verbose "HTTP: Enabled | HTTPS: Disabled"
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Log "Unable to establish an HTTP or HTTPS remoting session."
|
||||
Else {
|
||||
Write-ProgressLog "Unable to establish an HTTP or HTTPS remoting session."
|
||||
Throw "Unable to establish an HTTP or HTTPS remoting session."
|
||||
}
|
||||
Write-VerboseLog "PS Remoting has been successfully configured for Ansible."
|
||||
|
|
|
@ -165,7 +165,6 @@ test/integration/targets/win_exec_wrapper/tasks/main.yml no-smart-quotes # We a
|
|||
test/integration/targets/win_fetch/tasks/main.yml no-smart-quotes # We are explictly testing smart quotes in the file name to fetch
|
||||
test/integration/targets/win_module_utils/library/legacy_only_new_way_win_line_ending.ps1 line-endings # Explicitly tests that we still work with Windows line endings
|
||||
test/integration/targets/win_module_utils/library/legacy_only_old_way_win_line_ending.ps1 line-endings # Explicitly tests that we still work with Windows line endings
|
||||
test/integration/targets/win_script/files/test_script_creates_file.ps1 pslint:PSAvoidUsingCmdletAliases
|
||||
test/integration/targets/win_script/files/test_script.ps1 pslint:PSAvoidUsingWriteHost # Keep
|
||||
test/integration/targets/win_script/files/test_script_removes_file.ps1 pslint:PSCustomUseLiteralPath
|
||||
test/integration/targets/win_script/files/test_script_with_args.ps1 pslint:PSAvoidUsingWriteHost # Keep
|
||||
|
@ -196,16 +195,26 @@ test/support/network-integration/collections/ansible_collections/cisco/ios/plugi
|
|||
test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/cliconf/vyos.py pylint:arguments-renamed
|
||||
test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/modules/vyos_command.py pep8:E231
|
||||
test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/modules/vyos_command.py pylint:disallowed-name
|
||||
test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/module_utils/WebRequest.psm1 pslint!skip
|
||||
test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_uri.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/async_status.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/setup.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/slurp.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_acl.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_certificate_store.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_command.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_copy.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_dsc.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_feature.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_find.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_file.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_get_url.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_lineinfile.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_regedit.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_shell.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_stat.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_tempfile.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_user_right.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_user.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_wait_for.ps1 pslint!skip
|
||||
test/support/windows-integration/plugins/modules/win_whoami.ps1 pslint!skip
|
||||
test/units/executor/test_play_iterator.py pylint:disallowed-name
|
||||
test/units/modules/test_apt.py pylint:disallowed-name
|
||||
test/units/module_utils/basic/test_deprecate_warn.py pylint:ansible-deprecated-no-version
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
#!powershell
|
||||
|
||||
# Copyright: 2019, rnsc(@rnsc) <github@rnsc.be>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
|
||||
#AnsibleRequires -CSharpUtil Ansible.Basic
|
||||
#AnsibleRequires -OSVersion 6.3
|
||||
|
||||
$spec = @{
|
||||
options = @{
|
||||
drive_letter = @{ type = "str"; required = $true }
|
||||
state = @{ type = "str"; choices = "absent", "present"; default = "present"; }
|
||||
settings = @{
|
||||
type = "dict"
|
||||
required = $false
|
||||
options = @{
|
||||
minimum_file_size = @{ type = "int"; default = 32768 }
|
||||
minimum_file_age_days = @{ type = "int"; default = 2 }
|
||||
no_compress = @{ type = "bool"; required = $false; default = $false }
|
||||
optimize_in_use_files = @{ type = "bool"; required = $false; default = $false }
|
||||
verify = @{ type = "bool"; required = $false; default = $false }
|
||||
}
|
||||
}
|
||||
}
|
||||
supports_check_mode = $true
|
||||
}
|
||||
|
||||
$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
|
||||
|
||||
$drive_letter = $module.Params.drive_letter
|
||||
$state = $module.Params.state
|
||||
$settings = $module.Params.settings
|
||||
|
||||
$module.Result.changed = $false
|
||||
$module.Result.reboot_required = $false
|
||||
$module.Result.msg = ""
|
||||
|
||||
function Set-DataDeduplication($volume, $state, $settings, $dedup_job) {
|
||||
|
||||
$current_state = 'absent'
|
||||
|
||||
try {
|
||||
$dedup_info = Get-DedupVolume -Volume "$($volume.DriveLetter):"
|
||||
} catch {
|
||||
$dedup_info = $null
|
||||
}
|
||||
|
||||
if ($dedup_info.Enabled) {
|
||||
$current_state = 'present'
|
||||
}
|
||||
|
||||
if ( $state -ne $current_state ) {
|
||||
if( -not $module.CheckMode) {
|
||||
if($state -eq 'present') {
|
||||
# Enable-DedupVolume -Volume <String>
|
||||
Enable-DedupVolume -Volume "$($volume.DriveLetter):"
|
||||
} elseif ($state -eq 'absent') {
|
||||
Disable-DedupVolume -Volume "$($volume.DriveLetter):"
|
||||
}
|
||||
}
|
||||
$module.Result.changed = $true
|
||||
}
|
||||
|
||||
if ($state -eq 'present') {
|
||||
if ($null -ne $settings) {
|
||||
Set-DataDedupJobSettings -volume $volume -settings $settings
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Set-DataDedupJobSettings ($volume, $settings) {
|
||||
|
||||
try {
|
||||
$dedup_info = Get-DedupVolume -Volume "$($volume.DriveLetter):"
|
||||
} catch {
|
||||
$dedup_info = $null
|
||||
}
|
||||
|
||||
ForEach ($key in $settings.keys) {
|
||||
|
||||
# See Microsoft documentation:
|
||||
# https://docs.microsoft.com/en-us/powershell/module/deduplication/set-dedupvolume?view=win10-ps
|
||||
|
||||
$update_key = $key
|
||||
$update_value = $settings.$($key)
|
||||
# Transform Ansible style options to Powershell params
|
||||
$update_key = $update_key -replace('_', '')
|
||||
|
||||
if ($update_key -eq "MinimumFileSize" -and $update_value -lt 32768) {
|
||||
$update_value = 32768
|
||||
}
|
||||
|
||||
$current_value = ($dedup_info | Select-Object -ExpandProperty $update_key)
|
||||
|
||||
if ($update_value -ne $current_value) {
|
||||
$command_param = @{
|
||||
$($update_key) = $update_value
|
||||
}
|
||||
|
||||
# Set-DedupVolume -Volume <String>`
|
||||
# -NoCompress <bool> `
|
||||
# -MinimumFileAgeDays <UInt32> `
|
||||
# -MinimumFileSize <UInt32> (minimum 32768)
|
||||
if( -not $module.CheckMode ) {
|
||||
Set-DedupVolume -Volume "$($volume.DriveLetter):" @command_param
|
||||
}
|
||||
|
||||
$module.Result.changed = $true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Install required feature
|
||||
$feature_name = "FS-Data-Deduplication"
|
||||
if( -not $module.CheckMode) {
|
||||
$feature = Install-WindowsFeature -Name $feature_name
|
||||
|
||||
if ($feature.RestartNeeded -eq 'Yes') {
|
||||
$module.Result.reboot_required = $true
|
||||
$module.FailJson("$feature_name was installed but requires Windows to be rebooted to work.")
|
||||
}
|
||||
}
|
||||
|
||||
$volume = Get-Volume -DriveLetter $drive_letter
|
||||
|
||||
Set-DataDeduplication -volume $volume -state $state -settings $settings -dedup_job $dedup_job
|
||||
|
||||
$module.ExitJson()
|
|
@ -1,87 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: 2019, rnsc(@rnsc) <github@rnsc.be>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: win_data_deduplication
|
||||
version_added: "2.10"
|
||||
short_description: Module to enable Data Deduplication on a volume.
|
||||
description:
|
||||
- This module can be used to enable Data Deduplication on a Windows volume.
|
||||
- The module will install the FS-Data-Deduplication feature (a reboot will be necessary).
|
||||
options:
|
||||
drive_letter:
|
||||
description:
|
||||
- Windows drive letter on which to enable data deduplication.
|
||||
required: yes
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Wether to enable or disable data deduplication on the selected volume.
|
||||
default: present
|
||||
type: str
|
||||
choices: [ present, absent ]
|
||||
settings:
|
||||
description:
|
||||
- Dictionary of settings to pass to the Set-DedupVolume powershell command.
|
||||
type: dict
|
||||
suboptions:
|
||||
minimum_file_size:
|
||||
description:
|
||||
- Minimum file size you want to target for deduplication.
|
||||
- It will default to 32768 if not defined or if the value is less than 32768.
|
||||
type: int
|
||||
default: 32768
|
||||
minimum_file_age_days:
|
||||
description:
|
||||
- Minimum file age you want to target for deduplication.
|
||||
type: int
|
||||
default: 2
|
||||
no_compress:
|
||||
description:
|
||||
- Wether you want to enabled filesystem compression or not.
|
||||
type: bool
|
||||
default: no
|
||||
optimize_in_use_files:
|
||||
description:
|
||||
- Indicates that the server attempts to optimize currently open files.
|
||||
type: bool
|
||||
default: no
|
||||
verify:
|
||||
description:
|
||||
- Indicates whether the deduplication engine performs a byte-for-byte verification for each duplicate chunk
|
||||
that optimization creates, rather than relying on a cryptographically strong hash.
|
||||
- This option is not recommend.
|
||||
- Setting this parameter to True can degrade optimization performance.
|
||||
type: bool
|
||||
default: no
|
||||
author:
|
||||
- rnsc (@rnsc)
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Enable Data Deduplication on D
|
||||
win_data_deduplication:
|
||||
drive_letter: 'D'
|
||||
state: present
|
||||
|
||||
- name: Enable Data Deduplication on D
|
||||
win_data_deduplication:
|
||||
drive_letter: 'D'
|
||||
state: present
|
||||
settings:
|
||||
no_compress: true
|
||||
minimum_file_age_days: 1
|
||||
minimum_file_size: 0
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
#
|
||||
'''
|
|
@ -1,398 +0,0 @@
|
|||
#!powershell
|
||||
|
||||
# Copyright: (c) 2015, Trond Hindenes <trond@hindenes.com>, and others
|
||||
# Copyright: (c) 2017, Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
#AnsibleRequires -CSharpUtil Ansible.Basic
|
||||
#Requires -Version 5
|
||||
|
||||
Function ConvertTo-ArgSpecType {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Converts the DSC parameter type to the arg spec type required for Ansible.
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][String]$CimType
|
||||
)
|
||||
|
||||
$arg_type = switch($CimType) {
|
||||
Boolean { "bool" }
|
||||
Char16 { [Func[[Object], [Char]]]{ [System.Char]::Parse($args[0].ToString()) } }
|
||||
DateTime { [Func[[Object], [DateTime]]]{ [System.DateTime]($args[0].ToString()) } }
|
||||
Instance { "dict" }
|
||||
Real32 { "float" }
|
||||
Real64 { [Func[[Object], [Double]]]{ [System.Double]::Parse($args[0].ToString()) } }
|
||||
Reference { "dict" }
|
||||
SInt16 { [Func[[Object], [Int16]]]{ [System.Int16]::Parse($args[0].ToString()) } }
|
||||
SInt32 { "int" }
|
||||
SInt64 { [Func[[Object], [Int64]]]{ [System.Int64]::Parse($args[0].ToString()) } }
|
||||
SInt8 { [Func[[Object], [SByte]]]{ [System.SByte]::Parse($args[0].ToString()) } }
|
||||
String { "str" }
|
||||
UInt16 { [Func[[Object], [UInt16]]]{ [System.UInt16]::Parse($args[0].ToString()) } }
|
||||
UInt32 { [Func[[Object], [UInt32]]]{ [System.UInt32]::Parse($args[0].ToString()) } }
|
||||
UInt64 { [Func[[Object], [UInt64]]]{ [System.UInt64]::Parse($args[0].ToString()) } }
|
||||
UInt8 { [Func[[Object], [Byte]]]{ [System.Byte]::Parse($args[0].ToString()) } }
|
||||
Unknown { "raw" }
|
||||
default { "raw" }
|
||||
}
|
||||
return $arg_type
|
||||
}
|
||||
|
||||
Function Get-DscCimClassProperties {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get's a list of CimProperties of a CIM Class. It filters out any magic or
|
||||
read only properties that we don't need to know about.
|
||||
#>
|
||||
param([Parameter(Mandatory=$true)][String]$ClassName)
|
||||
|
||||
$resource = Get-CimClass -ClassName $ClassName -Namespace root\Microsoft\Windows\DesiredStateConfiguration
|
||||
|
||||
# Filter out any magic properties that are used internally on an OMI_BaseResource
|
||||
# https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/DscSupport/CimDSCParser.cs#L1203
|
||||
$magic_properties = @("ResourceId", "SourceInfo", "ModuleName", "ModuleVersion", "ConfigurationName")
|
||||
$properties = $resource.CimClassProperties | Where-Object {
|
||||
|
||||
($resource.CimSuperClassName -ne "OMI_BaseResource" -or $_.Name -notin $magic_properties) -and
|
||||
-not $_.Flags.HasFlag([Microsoft.Management.Infrastructure.CimFlags]::ReadOnly)
|
||||
}
|
||||
|
||||
return ,$properties
|
||||
}
|
||||
|
||||
Function Add-PropertyOption {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Adds the spec for the property type to the existing module specification.
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][Hashtable]$Spec,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[Microsoft.Management.Infrastructure.CimPropertyDeclaration]$Property
|
||||
)
|
||||
|
||||
$option = @{
|
||||
required = $false
|
||||
}
|
||||
$property_name = $Property.Name
|
||||
$property_type = $Property.CimType.ToString()
|
||||
|
||||
if ($Property.Flags.HasFlag([Microsoft.Management.Infrastructure.CimFlags]::Key) -or
|
||||
$Property.Flags.HasFlag([Microsoft.Management.Infrastructure.CimFlags]::Required)) {
|
||||
$option.required = $true
|
||||
}
|
||||
|
||||
if ($null -ne $Property.Qualifiers['Values']) {
|
||||
$option.choices = [System.Collections.Generic.List`1[Object]]$Property.Qualifiers['Values'].Value
|
||||
}
|
||||
|
||||
if ($property_name -eq "Name") {
|
||||
# For backwards compatibility we support specifying the Name DSC property as item_name
|
||||
$option.aliases = @("item_name")
|
||||
} elseif ($property_name -ceq "key") {
|
||||
# There seems to be a bug in the CIM property parsing when the property name is 'Key'. The CIM instance will
|
||||
# think the name is 'key' when the MOF actually defines it as 'Key'. We set the proper casing so the module arg
|
||||
# validator won't fire a case sensitive warning
|
||||
$property_name = "Key"
|
||||
}
|
||||
|
||||
if ($Property.ReferenceClassName -eq "MSFT_Credential") {
|
||||
# Special handling for the MSFT_Credential type (PSCredential), we handle this with having 2 options that
|
||||
# have the suffix _username and _password.
|
||||
$option_spec_pass = @{
|
||||
type = "str"
|
||||
required = $option.required
|
||||
no_log = $true
|
||||
}
|
||||
$Spec.options."$($property_name)_password" = $option_spec_pass
|
||||
$Spec.required_together.Add(@("$($property_name)_username", "$($property_name)_password")) > $null
|
||||
|
||||
$property_name = "$($property_name)_username"
|
||||
$option.type = "str"
|
||||
} elseif ($Property.ReferenceClassName -eq "MSFT_KeyValuePair") {
|
||||
$option.type = "dict"
|
||||
} elseif ($property_type.EndsWith("Array")) {
|
||||
$option.type = "list"
|
||||
$option.elements = ConvertTo-ArgSpecType -CimType $property_type.Substring(0, $property_type.Length - 5)
|
||||
} else {
|
||||
$option.type = ConvertTo-ArgSpecType -CimType $property_type
|
||||
}
|
||||
|
||||
if (($option.type -eq "dict" -or ($option.type -eq "list" -and $option.elements -eq "dict")) -and
|
||||
$Property.ReferenceClassName -ne "MSFT_KeyValuePair") {
|
||||
# Get the sub spec if the type is a Instance (CimInstance/dict)
|
||||
$sub_option_spec = Get-OptionSpec -ClassName $Property.ReferenceClassName
|
||||
$option += $sub_option_spec
|
||||
}
|
||||
|
||||
$Spec.options.$property_name = $option
|
||||
}
|
||||
|
||||
Function Get-OptionSpec {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Generates the specifiec used in AnsibleModule for a CIM MOF resource name.
|
||||
|
||||
.NOTES
|
||||
This won't be able to retrieve the default values for an option as that is not defined in the MOF for a resource.
|
||||
Default values are still preserved in the DSC engine if we don't pass in the property at all, we just can't report
|
||||
on what they are automatically.
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][String]$ClassName
|
||||
)
|
||||
|
||||
$spec = @{
|
||||
options = @{}
|
||||
required_together = [System.Collections.ArrayList]@()
|
||||
}
|
||||
$properties = Get-DscCimClassProperties -ClassName $ClassName
|
||||
foreach ($property in $properties) {
|
||||
Add-PropertyOption -Spec $spec -Property $property
|
||||
}
|
||||
|
||||
return $spec
|
||||
}
|
||||
|
||||
Function ConvertTo-CimInstance {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Converts a dict to a CimInstance of the specified Class. Also provides a
|
||||
better error message if this fails that contains the option name that failed.
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][String]$Name,
|
||||
[Parameter(Mandatory=$true)][String]$ClassName,
|
||||
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Value,
|
||||
[Parameter(Mandatory=$true)][Ansible.Basic.AnsibleModule]$Module,
|
||||
[Switch]$Recurse
|
||||
)
|
||||
|
||||
$properties = @{}
|
||||
foreach ($value_info in $Value.GetEnumerator()) {
|
||||
# Need to remove all null values from existing dict so the conversion works
|
||||
if ($null -eq $value_info.Value) {
|
||||
continue
|
||||
}
|
||||
$properties.($value_info.Key) = $value_info.Value
|
||||
}
|
||||
|
||||
if ($Recurse) {
|
||||
# We want to validate and convert and values to what's required by DSC
|
||||
$properties = ConvertTo-DscProperty -ClassName $ClassName -Params $properties -Module $Module
|
||||
}
|
||||
|
||||
try {
|
||||
return (New-CimInstance -ClassName $ClassName -Property $properties -ClientOnly)
|
||||
} catch {
|
||||
# New-CimInstance raises a poor error message, make sure we mention what option it is for
|
||||
$Module.FailJson("Failed to cast dict value for option '$Name' to a CimInstance: $($_.Exception.Message)", $_)
|
||||
}
|
||||
}
|
||||
|
||||
Function ConvertTo-DscProperty {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Converts the input module parameters that have been validated and casted
|
||||
into the types expected by the DSC engine. This is mostly done to deal with
|
||||
types like PSCredential and Dictionaries.
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][String]$ClassName,
|
||||
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Params,
|
||||
[Parameter(Mandatory=$true)][Ansible.Basic.AnsibleModule]$Module
|
||||
)
|
||||
$properties = Get-DscCimClassProperties -ClassName $ClassName
|
||||
|
||||
$dsc_properties = @{}
|
||||
foreach ($property in $properties) {
|
||||
$property_name = $property.Name
|
||||
$property_type = $property.CimType.ToString()
|
||||
|
||||
if ($property.ReferenceClassName -eq "MSFT_Credential") {
|
||||
$username = $Params."$($property_name)_username"
|
||||
$password = $Params."$($property_name)_password"
|
||||
|
||||
# No user set == No option set in playbook, skip this property
|
||||
if ($null -eq $username) {
|
||||
continue
|
||||
}
|
||||
$sec_password = ConvertTo-SecureString -String $password -AsPlainText -Force
|
||||
$value = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $sec_password
|
||||
} else {
|
||||
$value = $Params.$property_name
|
||||
|
||||
# The actual value wasn't set, skip adding this property
|
||||
if ($null -eq $value) {
|
||||
continue
|
||||
}
|
||||
|
||||
if ($property.ReferenceClassName -eq "MSFT_KeyValuePair") {
|
||||
$key_value_pairs = [System.Collections.Generic.List`1[CimInstance]]@()
|
||||
foreach ($value_info in $value.GetEnumerator()) {
|
||||
$kvp = @{Key = $value_info.Key; Value = $value_info.Value.ToString()}
|
||||
$cim_instance = ConvertTo-CimInstance -Name $property_name -ClassName MSFT_KeyValuePair `
|
||||
-Value $kvp -Module $Module
|
||||
$key_value_pairs.Add($cim_instance) > $null
|
||||
}
|
||||
$value = $key_value_pairs.ToArray()
|
||||
} elseif ($null -ne $property.ReferenceClassName) {
|
||||
# Convert the dict to a CimInstance (or list of CimInstances)
|
||||
$convert_args = @{
|
||||
ClassName = $property.ReferenceClassName
|
||||
Module = $Module
|
||||
Name = $property_name
|
||||
Recurse = $true
|
||||
}
|
||||
if ($property_type.EndsWith("Array")) {
|
||||
$value = [System.Collections.Generic.List`1[CimInstance]]@()
|
||||
foreach ($raw in $Params.$property_name.GetEnumerator()) {
|
||||
$cim_instance = ConvertTo-CimInstance -Value $raw @convert_args
|
||||
$value.Add($cim_instance) > $null
|
||||
}
|
||||
$value = $value.ToArray() # Need to make sure we are dealing with an Array not a List
|
||||
} else {
|
||||
$value = ConvertTo-CimInstance -Value $value @convert_args
|
||||
}
|
||||
}
|
||||
}
|
||||
$dsc_properties.$property_name = $value
|
||||
}
|
||||
|
||||
return $dsc_properties
|
||||
}
|
||||
|
||||
Function Invoke-DscMethod {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Invokes the DSC Resource Method specified in another PS pipeline. This is
|
||||
done so we can retrieve the Verbose stream and return it back to the user
|
||||
for futher debugging.
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][Ansible.Basic.AnsibleModule]$Module,
|
||||
[Parameter(Mandatory=$true)][String]$Method,
|
||||
[Parameter(Mandatory=$true)][Hashtable]$Arguments
|
||||
)
|
||||
|
||||
# Invoke the DSC resource in a separate runspace so we can capture the Verbose output
|
||||
$ps = [PowerShell]::Create()
|
||||
$ps.AddCommand("Invoke-DscResource").AddParameter("Method", $Method) > $null
|
||||
$ps.AddParameters($Arguments) > $null
|
||||
|
||||
$result = $ps.Invoke()
|
||||
|
||||
# Pass the warnings through to the AnsibleModule return result
|
||||
foreach ($warning in $ps.Streams.Warning) {
|
||||
$Module.Warn($warning.Message)
|
||||
}
|
||||
|
||||
# If running at a high enough verbosity, add the verbose output to the AnsibleModule return result
|
||||
if ($Module.Verbosity -ge 3) {
|
||||
$verbose_logs = [System.Collections.Generic.List`1[String]]@()
|
||||
foreach ($verbosity in $ps.Streams.Verbose) {
|
||||
$verbose_logs.Add($verbosity.Message) > $null
|
||||
}
|
||||
$Module.Result."verbose_$($Method.ToLower())" = $verbose_logs
|
||||
}
|
||||
|
||||
if ($ps.HadErrors) {
|
||||
# Cannot pass in the ErrorRecord as it's a RemotingErrorRecord and doesn't contain the ScriptStackTrace
|
||||
# or other info that would be useful
|
||||
$Module.FailJson("Failed to invoke DSC $Method method: $($ps.Streams.Error[0].Exception.Message)")
|
||||
}
|
||||
|
||||
return $result
|
||||
}
|
||||
|
||||
# win_dsc is unique in that is builds the arg spec based on DSC Resource input. To get this info
|
||||
# we need to read the resource_name and module_version value which is done outside of Ansible.Basic
|
||||
if ($args.Length -gt 0) {
|
||||
$params = Get-Content -Path $args[0] | ConvertFrom-Json
|
||||
} else {
|
||||
$params = $complex_args
|
||||
}
|
||||
if (-not $params.ContainsKey("resource_name")) {
|
||||
$res = @{
|
||||
msg = "missing required argument: resource_name"
|
||||
failed = $true
|
||||
}
|
||||
Write-Output -InputObject (ConvertTo-Json -Compress -InputObject $res)
|
||||
exit 1
|
||||
}
|
||||
$resource_name = $params.resource_name
|
||||
|
||||
if ($params.ContainsKey("module_version")) {
|
||||
$module_version = $params.module_version
|
||||
} else {
|
||||
$module_version = "latest"
|
||||
}
|
||||
|
||||
$module_versions = (Get-DscResource -Name $resource_name -ErrorAction SilentlyContinue | Sort-Object -Property Version)
|
||||
$resource = $null
|
||||
if ($module_version -eq "latest" -and $null -ne $module_versions) {
|
||||
$resource = $module_versions[-1]
|
||||
} elseif ($module_version -ne "latest") {
|
||||
$resource = $module_versions | Where-Object { $_.Version -eq $module_version }
|
||||
}
|
||||
|
||||
if (-not $resource) {
|
||||
if ($module_version -eq "latest") {
|
||||
$msg = "Resource '$resource_name' not found."
|
||||
} else {
|
||||
$msg = "Resource '$resource_name' with version '$module_version' not found."
|
||||
$msg += " Versions installed: '$($module_versions.Version -join "', '")'."
|
||||
}
|
||||
|
||||
Write-Output -InputObject (ConvertTo-Json -Compress -InputObject @{ failed = $true; msg = $msg })
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Build the base args for the DSC Invocation based on the resource selected
|
||||
$dsc_args = @{
|
||||
Name = $resource.Name
|
||||
}
|
||||
|
||||
# Binary resources are not working very well with that approach - need to guesstimate module name/version
|
||||
$module_version = $null
|
||||
if ($resource.Module) {
|
||||
$dsc_args.ModuleName = @{
|
||||
ModuleName = $resource.Module.Name
|
||||
ModuleVersion = $resource.Module.Version
|
||||
}
|
||||
$module_version = $resource.Module.Version.ToString()
|
||||
} else {
|
||||
$dsc_args.ModuleName = "PSDesiredStateConfiguration"
|
||||
}
|
||||
|
||||
# To ensure the class registered with CIM is the one based on our version, we want to run the Get method so the DSC
|
||||
# engine updates the metadata propery. We don't care about any errors here
|
||||
try {
|
||||
Invoke-DscResource -Method Get -Property @{Fake="Fake"} @dsc_args > $null
|
||||
} catch {}
|
||||
|
||||
# Dynamically build the option spec based on the resource_name specified and create the module object
|
||||
$spec = Get-OptionSpec -ClassName $resource.ResourceType
|
||||
$spec.supports_check_mode = $true
|
||||
$spec.options.module_version = @{ type = "str"; default = "latest" }
|
||||
$spec.options.resource_name = @{ type = "str"; required = $true }
|
||||
|
||||
$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
|
||||
$module.Result.reboot_required = $false
|
||||
$module.Result.module_version = $module_version
|
||||
|
||||
# Build the DSC invocation arguments and invoke the resource
|
||||
$dsc_args.Property = ConvertTo-DscProperty -ClassName $resource.ResourceType -Module $module -Params $Module.Params
|
||||
$dsc_args.Verbose = $true
|
||||
|
||||
$test_result = Invoke-DscMethod -Module $module -Method Test -Arguments $dsc_args
|
||||
if ($test_result.InDesiredState -ne $true) {
|
||||
if (-not $module.CheckMode) {
|
||||
$result = Invoke-DscMethod -Module $module -Method Set -Arguments $dsc_args
|
||||
$module.Result.reboot_required = $result.RebootRequired
|
||||
}
|
||||
$module.Result.changed = $true
|
||||
}
|
||||
|
||||
$module.ExitJson()
|
|
@ -1,183 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2015, Trond Hindenes <trond@hindenes.com>, and others
|
||||
# Copyright: (c) 2017, Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: win_dsc
|
||||
version_added: "2.4"
|
||||
short_description: Invokes a PowerShell DSC configuration
|
||||
description:
|
||||
- Configures a resource using PowerShell DSC.
|
||||
- Requires PowerShell version 5.0 or newer.
|
||||
- Most of the options for this module are dynamic and will vary depending on
|
||||
the DSC Resource specified in I(resource_name).
|
||||
- See :doc:`/user_guide/windows_dsc` for more information on how to use this module.
|
||||
options:
|
||||
resource_name:
|
||||
description:
|
||||
- The name of the DSC Resource to use.
|
||||
- Must be accessible to PowerShell using any of the default paths.
|
||||
type: str
|
||||
required: yes
|
||||
module_version:
|
||||
description:
|
||||
- Can be used to configure the exact version of the DSC resource to be
|
||||
invoked.
|
||||
- Useful if the target node has multiple versions installed of the module
|
||||
containing the DSC resource.
|
||||
- If not specified, the module will follow standard PowerShell convention
|
||||
and use the highest version available.
|
||||
type: str
|
||||
default: latest
|
||||
free_form:
|
||||
description:
|
||||
- The M(win_dsc) module takes in multiple free form options based on the
|
||||
DSC resource being invoked by I(resource_name).
|
||||
- There is no option actually named C(free_form) so see the examples.
|
||||
- This module will try and convert the option to the correct type required
|
||||
by the DSC resource and throw a warning if it fails.
|
||||
- If the type of the DSC resource option is a C(CimInstance) or
|
||||
C(CimInstance[]), this means the value should be a dictionary or list
|
||||
of dictionaries based on the values required by that option.
|
||||
- If the type of the DSC resource option is a C(PSCredential) then there
|
||||
needs to be 2 options set in the Ansible task definition suffixed with
|
||||
C(_username) and C(_password).
|
||||
- If the type of the DSC resource option is an array, then a list should be
|
||||
provided but a comma separated string also work. Use a list where
|
||||
possible as no escaping is required and it works with more complex types
|
||||
list C(CimInstance[]).
|
||||
- If the type of the DSC resource option is a C(DateTime), you should use
|
||||
a string in the form of an ISO 8901 string to ensure the exact date is
|
||||
used.
|
||||
- Since Ansible 2.8, Ansible will now validate the input fields against the
|
||||
DSC resource definition automatically. Older versions will silently
|
||||
ignore invalid fields.
|
||||
type: str
|
||||
required: true
|
||||
notes:
|
||||
- By default there are a few builtin resources that come with PowerShell 5.0,
|
||||
see U(https://docs.microsoft.com/en-us/powershell/scripting/dsc/resources/resources) for
|
||||
more information on these resources.
|
||||
- Custom DSC resources can be installed with M(win_psmodule) using the I(name)
|
||||
option.
|
||||
- The DSC engine run's each task as the SYSTEM account, any resources that need
|
||||
to be accessed with a different account need to have C(PsDscRunAsCredential)
|
||||
set.
|
||||
- To see the valid options for a DSC resource, run the module with C(-vvv) to
|
||||
show the possible module invocation. Default values are not shown in this
|
||||
output but are applied within the DSC engine.
|
||||
author:
|
||||
- Trond Hindenes (@trondhindenes)
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Extract zip file
|
||||
win_dsc:
|
||||
resource_name: Archive
|
||||
Ensure: Present
|
||||
Path: C:\Temp\zipfile.zip
|
||||
Destination: C:\Temp\Temp2
|
||||
|
||||
- name: Install a Windows feature with the WindowsFeature resource
|
||||
win_dsc:
|
||||
resource_name: WindowsFeature
|
||||
Name: telnet-client
|
||||
|
||||
- name: Edit HKCU reg key under specific user
|
||||
win_dsc:
|
||||
resource_name: Registry
|
||||
Ensure: Present
|
||||
Key: HKEY_CURRENT_USER\ExampleKey
|
||||
ValueName: TestValue
|
||||
ValueData: TestData
|
||||
PsDscRunAsCredential_username: '{{ansible_user}}'
|
||||
PsDscRunAsCredential_password: '{{ansible_password}}'
|
||||
no_log: true
|
||||
|
||||
- name: Create file with multiple attributes
|
||||
win_dsc:
|
||||
resource_name: File
|
||||
DestinationPath: C:\ansible\dsc
|
||||
Attributes: # can also be a comma separated string, e.g. 'Hidden, System'
|
||||
- Hidden
|
||||
- System
|
||||
Ensure: Present
|
||||
Type: Directory
|
||||
|
||||
- name: Call DSC resource with DateTime option
|
||||
win_dsc:
|
||||
resource_name: DateTimeResource
|
||||
DateTimeOption: '2019-02-22T13:57:31.2311892+00:00'
|
||||
|
||||
# more complex example using custom DSC resource and dict values
|
||||
- name: Setup the xWebAdministration module
|
||||
win_psmodule:
|
||||
name: xWebAdministration
|
||||
state: present
|
||||
|
||||
- name: Create IIS Website with Binding and Authentication options
|
||||
win_dsc:
|
||||
resource_name: xWebsite
|
||||
Ensure: Present
|
||||
Name: DSC Website
|
||||
State: Started
|
||||
PhysicalPath: C:\inetpub\wwwroot
|
||||
BindingInfo: # Example of a CimInstance[] DSC parameter (list of dicts)
|
||||
- Protocol: https
|
||||
Port: 1234
|
||||
CertificateStoreName: MY
|
||||
CertificateThumbprint: C676A89018C4D5902353545343634F35E6B3A659
|
||||
HostName: DSCTest
|
||||
IPAddress: '*'
|
||||
SSLFlags: '1'
|
||||
- Protocol: http
|
||||
Port: 4321
|
||||
IPAddress: '*'
|
||||
AuthenticationInfo: # Example of a CimInstance DSC parameter (dict)
|
||||
Anonymous: no
|
||||
Basic: true
|
||||
Digest: false
|
||||
Windows: yes
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
module_version:
|
||||
description: The version of the dsc resource/module used.
|
||||
returned: always
|
||||
type: str
|
||||
sample: "1.0.1"
|
||||
reboot_required:
|
||||
description: Flag returned from the DSC engine indicating whether or not
|
||||
the machine requires a reboot for the invoked changes to take effect.
|
||||
returned: always
|
||||
type: bool
|
||||
sample: true
|
||||
verbose_test:
|
||||
description: The verbose output as a list from executing the DSC test
|
||||
method.
|
||||
returned: Ansible verbosity is -vvv or greater
|
||||
type: list
|
||||
sample: [
|
||||
"Perform operation 'Invoke CimMethod' with the following parameters, ",
|
||||
"[SERVER]: LCM: [Start Test ] [[File]DirectResourceAccess]",
|
||||
"Operation 'Invoke CimMethod' complete."
|
||||
]
|
||||
verbose_set:
|
||||
description: The verbose output as a list from executing the DSC Set
|
||||
method.
|
||||
returned: Ansible verbosity is -vvv or greater and a change occurred
|
||||
type: list
|
||||
sample: [
|
||||
"Perform operation 'Invoke CimMethod' with the following parameters, ",
|
||||
"[SERVER]: LCM: [Start Set ] [[File]DirectResourceAccess]",
|
||||
"Operation 'Invoke CimMethod' complete."
|
||||
]
|
||||
'''
|
|
@ -1,111 +0,0 @@
|
|||
#!powershell
|
||||
|
||||
# Copyright: (c) 2014, Paul Durivage <paul.durivage@rackspace.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
#Requires -Module Ansible.ModuleUtils.Legacy
|
||||
|
||||
Import-Module -Name ServerManager
|
||||
|
||||
$result = @{
|
||||
changed = $false
|
||||
}
|
||||
|
||||
$params = Parse-Args $args -supports_check_mode $true
|
||||
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
|
||||
|
||||
$name = Get-AnsibleParam -obj $params -name "name" -type "list" -failifempty $true
|
||||
$state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "present","absent"
|
||||
|
||||
$include_sub_features = Get-AnsibleParam -obj $params -name "include_sub_features" -type "bool" -default $false
|
||||
$include_management_tools = Get-AnsibleParam -obj $params -name "include_management_tools" -type "bool" -default $false
|
||||
$source = Get-AnsibleParam -obj $params -name "source" -type "str"
|
||||
|
||||
$install_cmdlet = $false
|
||||
if (Get-Command -Name Install-WindowsFeature -ErrorAction SilentlyContinue) {
|
||||
Set-Alias -Name Install-AnsibleWindowsFeature -Value Install-WindowsFeature
|
||||
Set-Alias -Name Uninstall-AnsibleWindowsFeature -Value Uninstall-WindowsFeature
|
||||
$install_cmdlet = $true
|
||||
} elseif (Get-Command -Name Add-WindowsFeature -ErrorAction SilentlyContinue) {
|
||||
Set-Alias -Name Install-AnsibleWindowsFeature -Value Add-WindowsFeature
|
||||
Set-Alias -Name Uninstall-AnsibleWindowsFeature -Value Remove-WindowsFeature
|
||||
} else {
|
||||
Fail-Json -obj $result -message "This version of Windows does not support the cmdlets Install-WindowsFeature or Add-WindowsFeature"
|
||||
}
|
||||
|
||||
if ($state -eq "present") {
|
||||
$install_args = @{
|
||||
Name = $name
|
||||
IncludeAllSubFeature = $include_sub_features
|
||||
Restart = $false
|
||||
WhatIf = $check_mode
|
||||
ErrorAction = "Stop"
|
||||
}
|
||||
|
||||
if ($install_cmdlet) {
|
||||
$install_args.IncludeManagementTools = $include_management_tools
|
||||
$install_args.Confirm = $false
|
||||
if ($source) {
|
||||
if (-not (Test-Path -Path $source)) {
|
||||
Fail-Json -obj $result -message "Failed to find source path $source for feature install"
|
||||
}
|
||||
$install_args.Source = $source
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$action_results = Install-AnsibleWindowsFeature @install_args
|
||||
} catch {
|
||||
Fail-Json -obj $result -message "Failed to install Windows Feature: $($_.Exception.Message)"
|
||||
}
|
||||
} else {
|
||||
$uninstall_args = @{
|
||||
Name = $name
|
||||
Restart = $false
|
||||
WhatIf = $check_mode
|
||||
ErrorAction = "Stop"
|
||||
}
|
||||
if ($install_cmdlet) {
|
||||
$uninstall_args.IncludeManagementTools = $include_management_tools
|
||||
}
|
||||
|
||||
try {
|
||||
$action_results = Uninstall-AnsibleWindowsFeature @uninstall_args
|
||||
} catch {
|
||||
Fail-Json -obj $result -message "Failed to uninstall Windows Feature: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
# Loop through results and create a hash containing details about
|
||||
# each role/feature that is installed/removed
|
||||
# $action_results.FeatureResult is not empty if anything was changed
|
||||
$feature_results = @()
|
||||
foreach ($action_result in $action_results.FeatureResult) {
|
||||
$message = @()
|
||||
foreach ($msg in $action_result.Message) {
|
||||
$message += @{
|
||||
message_type = $msg.MessageType.ToString()
|
||||
error_code = $msg.ErrorCode
|
||||
text = $msg.Text
|
||||
}
|
||||
}
|
||||
|
||||
$feature_results += @{
|
||||
id = $action_result.Id
|
||||
display_name = $action_result.DisplayName
|
||||
message = $message
|
||||
reboot_required = ConvertTo-Bool -obj $action_result.RestartNeeded
|
||||
skip_reason = $action_result.SkipReason.ToString()
|
||||
success = ConvertTo-Bool -obj $action_result.Success
|
||||
restart_needed = ConvertTo-Bool -obj $action_result.RestartNeeded
|
||||
}
|
||||
$result.changed = $true
|
||||
}
|
||||
$result.feature_result = $feature_results
|
||||
$result.success = ConvertTo-Bool -obj $action_results.Success
|
||||
$result.exitcode = $action_results.ExitCode.ToString()
|
||||
$result.reboot_required = ConvertTo-Bool -obj $action_results.RestartNeeded
|
||||
# controls whether Ansible will fail or not
|
||||
$result.failed = (-not $action_results.Success)
|
||||
|
||||
Exit-Json -obj $result
|
|
@ -1,149 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2014, Paul Durivage <paul.durivage@rackspace.com>
|
||||
# Copyright: (c) 2014, Trond Hindenes <trond@hindenes.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: win_feature
|
||||
version_added: "1.7"
|
||||
short_description: Installs and uninstalls Windows Features on Windows Server
|
||||
description:
|
||||
- Installs or uninstalls Windows Roles or Features on Windows Server.
|
||||
- This module uses the Add/Remove-WindowsFeature Cmdlets on Windows 2008 R2
|
||||
and Install/Uninstall-WindowsFeature Cmdlets on Windows 2012, which are not available on client os machines.
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Names of roles or features to install as a single feature or a comma-separated list of features.
|
||||
- To list all available features use the PowerShell command C(Get-WindowsFeature).
|
||||
type: list
|
||||
required: yes
|
||||
state:
|
||||
description:
|
||||
- State of the features or roles on the system.
|
||||
type: str
|
||||
choices: [ absent, present ]
|
||||
default: present
|
||||
include_sub_features:
|
||||
description:
|
||||
- Adds all subfeatures of the specified feature.
|
||||
type: bool
|
||||
default: no
|
||||
include_management_tools:
|
||||
description:
|
||||
- Adds the corresponding management tools to the specified feature.
|
||||
- Not supported in Windows 2008 R2 and will be ignored.
|
||||
type: bool
|
||||
default: no
|
||||
source:
|
||||
description:
|
||||
- Specify a source to install the feature from.
|
||||
- Not supported in Windows 2008 R2 and will be ignored.
|
||||
- Can either be C({driveletter}:\sources\sxs) or C(\\{IP}\share\sources\sxs).
|
||||
type: str
|
||||
version_added: "2.1"
|
||||
seealso:
|
||||
- module: win_chocolatey
|
||||
- module: win_package
|
||||
author:
|
||||
- Paul Durivage (@angstwad)
|
||||
- Trond Hindenes (@trondhindenes)
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Install IIS (Web-Server only)
|
||||
win_feature:
|
||||
name: Web-Server
|
||||
state: present
|
||||
|
||||
- name: Install IIS (Web-Server and Web-Common-Http)
|
||||
win_feature:
|
||||
name:
|
||||
- Web-Server
|
||||
- Web-Common-Http
|
||||
state: present
|
||||
|
||||
- name: Install NET-Framework-Core from file
|
||||
win_feature:
|
||||
name: NET-Framework-Core
|
||||
source: C:\Temp\iso\sources\sxs
|
||||
state: present
|
||||
|
||||
- name: Install IIS Web-Server with sub features and management tools
|
||||
win_feature:
|
||||
name: Web-Server
|
||||
state: present
|
||||
include_sub_features: yes
|
||||
include_management_tools: yes
|
||||
register: win_feature
|
||||
|
||||
- name: Reboot if installing Web-Server feature requires it
|
||||
win_reboot:
|
||||
when: win_feature.reboot_required
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
exitcode:
|
||||
description: The stringified exit code from the feature installation/removal command.
|
||||
returned: always
|
||||
type: str
|
||||
sample: Success
|
||||
feature_result:
|
||||
description: List of features that were installed or removed.
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
contains:
|
||||
display_name:
|
||||
description: Feature display name.
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Telnet Client"
|
||||
id:
|
||||
description: A list of KB article IDs that apply to the update.
|
||||
returned: always
|
||||
type: int
|
||||
sample: 44
|
||||
message:
|
||||
description: Any messages returned from the feature subsystem that occurred during installation or removal of this feature.
|
||||
returned: always
|
||||
type: list
|
||||
elements: str
|
||||
sample: []
|
||||
reboot_required:
|
||||
description: True when the target server requires a reboot as a result of installing or removing this feature.
|
||||
returned: always
|
||||
type: bool
|
||||
sample: true
|
||||
restart_needed:
|
||||
description: DEPRECATED in Ansible 2.4 (refer to C(reboot_required) instead). True when the target server requires a reboot as a
|
||||
result of installing or removing this feature.
|
||||
returned: always
|
||||
type: bool
|
||||
sample: true
|
||||
skip_reason:
|
||||
description: The reason a feature installation or removal was skipped.
|
||||
returned: always
|
||||
type: str
|
||||
sample: NotSkipped
|
||||
success:
|
||||
description: If the feature installation or removal was successful.
|
||||
returned: always
|
||||
type: bool
|
||||
sample: true
|
||||
reboot_required:
|
||||
description: True when the target server requires a reboot to complete updates (no further updates can be installed until after a reboot).
|
||||
returned: success
|
||||
type: bool
|
||||
sample: true
|
||||
'''
|
|
@ -1,416 +0,0 @@
|
|||
#!powershell
|
||||
|
||||
# Copyright: (c) 2016, Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
#AnsibleRequires -CSharpUtil Ansible.Basic
|
||||
#Requires -Module Ansible.ModuleUtils.LinkUtil
|
||||
|
||||
$spec = @{
|
||||
options = @{
|
||||
paths = @{ type = "list"; elements = "str"; required = $true }
|
||||
age = @{ type = "str" }
|
||||
age_stamp = @{ type = "str"; default = "mtime"; choices = "mtime", "ctime", "atime" }
|
||||
file_type = @{ type = "str"; default = "file"; choices = "file", "directory" }
|
||||
follow = @{ type = "bool"; default = $false }
|
||||
hidden = @{ type = "bool"; default = $false }
|
||||
patterns = @{ type = "list"; elements = "str"; aliases = "regex", "regexp" }
|
||||
recurse = @{ type = "bool"; default = $false }
|
||||
size = @{ type = "str" }
|
||||
use_regex = @{ type = "bool"; default = $false }
|
||||
get_checksum = @{ type = "bool"; default = $true }
|
||||
checksum_algorithm = @{ type = "str"; default = "sha1"; choices = "md5", "sha1", "sha256", "sha384", "sha512" }
|
||||
}
|
||||
supports_check_mode = $true
|
||||
}
|
||||
|
||||
$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
|
||||
|
||||
$paths = $module.Params.paths
|
||||
$age = $module.Params.age
|
||||
$age_stamp = $module.Params.age_stamp
|
||||
$file_type = $module.Params.file_type
|
||||
$follow = $module.Params.follow
|
||||
$hidden = $module.Params.hidden
|
||||
$patterns = $module.Params.patterns
|
||||
$recurse = $module.Params.recurse
|
||||
$size = $module.Params.size
|
||||
$use_regex = $module.Params.use_regex
|
||||
$get_checksum = $module.Params.get_checksum
|
||||
$checksum_algorithm = $module.Params.checksum_algorithm
|
||||
|
||||
$module.Result.examined = 0
|
||||
$module.Result.files = @()
|
||||
$module.Result.matched = 0
|
||||
|
||||
Load-LinkUtils
|
||||
|
||||
Function Assert-Age {
|
||||
Param (
|
||||
[System.IO.FileSystemInfo]$File,
|
||||
[System.Int64]$Age,
|
||||
[System.String]$AgeStamp
|
||||
)
|
||||
|
||||
$actual_age = switch ($AgeStamp) {
|
||||
mtime { $File.LastWriteTime.Ticks }
|
||||
ctime { $File.CreationTime.Ticks }
|
||||
atime { $File.LastAccessTime.Ticks }
|
||||
}
|
||||
|
||||
if ($Age -ge 0) {
|
||||
return $Age -ge $actual_age
|
||||
} else {
|
||||
return ($Age * -1) -le $actual_age
|
||||
}
|
||||
}
|
||||
|
||||
Function Assert-FileType {
|
||||
Param (
|
||||
[System.IO.FileSystemInfo]$File,
|
||||
[System.String]$FileType
|
||||
)
|
||||
|
||||
$is_dir = $File.Attributes.HasFlag([System.IO.FileAttributes]::Directory)
|
||||
return ($FileType -eq 'directory' -and $is_dir) -or ($FileType -eq 'file' -and -not $is_dir)
|
||||
}
|
||||
|
||||
Function Assert-FileHidden {
|
||||
Param (
|
||||
[System.IO.FileSystemInfo]$File,
|
||||
[Switch]$IsHidden
|
||||
)
|
||||
|
||||
$file_is_hidden = $File.Attributes.HasFlag([System.IO.FileAttributes]::Hidden)
|
||||
return $IsHidden.IsPresent -eq $file_is_hidden
|
||||
}
|
||||
|
||||
|
||||
Function Assert-FileNamePattern {
|
||||
Param (
|
||||
[System.IO.FileSystemInfo]$File,
|
||||
[System.String[]]$Patterns,
|
||||
[Switch]$UseRegex
|
||||
)
|
||||
|
||||
$valid_match = $false
|
||||
foreach ($pattern in $Patterns) {
|
||||
if ($UseRegex) {
|
||||
if ($File.Name -match $pattern) {
|
||||
$valid_match = $true
|
||||
break
|
||||
}
|
||||
} else {
|
||||
if ($File.Name -like $pattern) {
|
||||
$valid_match = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return $valid_match
|
||||
}
|
||||
|
||||
Function Assert-FileSize {
|
||||
Param (
|
||||
[System.IO.FileSystemInfo]$File,
|
||||
[System.Int64]$Size
|
||||
)
|
||||
|
||||
if ($Size -ge 0) {
|
||||
return $File.Length -ge $Size
|
||||
} else {
|
||||
return $File.Length -le ($Size * -1)
|
||||
}
|
||||
}
|
||||
|
||||
Function Get-FileChecksum {
|
||||
Param (
|
||||
[System.String]$Path,
|
||||
[System.String]$Algorithm
|
||||
)
|
||||
|
||||
$sp = switch ($algorithm) {
|
||||
'md5' { New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider }
|
||||
'sha1' { New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider }
|
||||
'sha256' { New-Object -TypeName System.Security.Cryptography.SHA256CryptoServiceProvider }
|
||||
'sha384' { New-Object -TypeName System.Security.Cryptography.SHA384CryptoServiceProvider }
|
||||
'sha512' { New-Object -TypeName System.Security.Cryptography.SHA512CryptoServiceProvider }
|
||||
}
|
||||
|
||||
$fp = [System.IO.File]::Open($Path, [System.IO.Filemode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
|
||||
try {
|
||||
$hash = [System.BitConverter]::ToString($sp.ComputeHash($fp)).Replace("-", "").ToLower()
|
||||
} finally {
|
||||
$fp.Dispose()
|
||||
}
|
||||
|
||||
return $hash
|
||||
}
|
||||
|
||||
Function Search-Path {
|
||||
[CmdletBinding()]
|
||||
Param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[System.String]
|
||||
$Path,
|
||||
|
||||
[Parameter(Mandatory=$true)]
|
||||
[AllowEmptyCollection()]
|
||||
[System.Collections.Generic.HashSet`1[System.String]]
|
||||
$CheckedPaths,
|
||||
|
||||
[Parameter(Mandatory=$true)]
|
||||
[Object]
|
||||
$Module,
|
||||
|
||||
[System.Int64]
|
||||
$Age,
|
||||
|
||||
[System.String]
|
||||
$AgeStamp,
|
||||
|
||||
[System.String]
|
||||
$FileType,
|
||||
|
||||
[Switch]
|
||||
$Follow,
|
||||
|
||||
[Switch]
|
||||
$GetChecksum,
|
||||
|
||||
[Switch]
|
||||
$IsHidden,
|
||||
|
||||
[System.String[]]
|
||||
$Patterns,
|
||||
|
||||
[Switch]
|
||||
$Recurse,
|
||||
|
||||
[System.Int64]
|
||||
$Size,
|
||||
|
||||
[Switch]
|
||||
$UseRegex
|
||||
)
|
||||
|
||||
$dir_obj = New-Object -TypeName System.IO.DirectoryInfo -ArgumentList $Path
|
||||
if ([Int32]$dir_obj.Attributes -eq -1) {
|
||||
$Module.Warn("Argument path '$Path' does not exist, skipping")
|
||||
return
|
||||
} elseif (-not $dir_obj.Attributes.HasFlag([System.IO.FileAttributes]::Directory)) {
|
||||
$Module.Warn("Argument path '$Path' is a file not a directory, skipping")
|
||||
return
|
||||
}
|
||||
|
||||
$dir_files = @()
|
||||
try {
|
||||
$dir_files = $dir_obj.EnumerateFileSystemInfos("*", [System.IO.SearchOption]::TopDirectoryOnly)
|
||||
} catch [System.IO.DirectoryNotFoundException] { # Broken ReparsePoint/Symlink, cannot enumerate
|
||||
} catch [System.UnauthorizedAccessException] {} # No ListDirectory permissions, Get-ChildItem ignored this
|
||||
|
||||
foreach ($dir_child in $dir_files) {
|
||||
if ($dir_child.Attributes.HasFlag([System.IO.FileAttributes]::Directory) -and $Recurse) {
|
||||
if ($Follow -or -not $dir_child.Attributes.HasFlag([System.IO.FileAttributes]::ReparsePoint)) {
|
||||
$PSBoundParameters.Remove('Path') > $null
|
||||
Search-Path -Path $dir_child.FullName @PSBoundParameters
|
||||
}
|
||||
}
|
||||
|
||||
# Check to see if we've already encountered this path and skip if we have.
|
||||
if (-not $CheckedPaths.Add($dir_child.FullName.ToLowerInvariant())) {
|
||||
continue
|
||||
}
|
||||
|
||||
$Module.Result.examined++
|
||||
|
||||
if ($PSBoundParameters.ContainsKey('Age')) {
|
||||
$age_match = Assert-Age -File $dir_child -Age $Age -AgeStamp $AgeStamp
|
||||
} else {
|
||||
$age_match = $true
|
||||
}
|
||||
|
||||
$file_type_match = Assert-FileType -File $dir_child -FileType $FileType
|
||||
$hidden_match = Assert-FileHidden -File $dir_child -IsHidden:$IsHidden
|
||||
|
||||
if ($PSBoundParameters.ContainsKey('Patterns')) {
|
||||
$pattern_match = Assert-FileNamePattern -File $dir_child -Patterns $Patterns -UseRegex:$UseRegex.IsPresent
|
||||
} else {
|
||||
$pattern_match = $true
|
||||
}
|
||||
|
||||
if ($PSBoundParameters.ContainsKey('Size')) {
|
||||
$size_match = Assert-FileSize -File $dir_child -Size $Size
|
||||
} else {
|
||||
$size_match = $true
|
||||
}
|
||||
|
||||
if (-not ($age_match -and $file_type_match -and $hidden_match -and $pattern_match -and $size_match)) {
|
||||
continue
|
||||
}
|
||||
|
||||
# It passed all our filters so add it
|
||||
$module.Result.matched++
|
||||
|
||||
# TODO: Make this generic so it can be shared with win_find and win_stat.
|
||||
$epoch = New-Object -Type System.DateTime -ArgumentList 1970, 1, 1, 0, 0, 0, 0
|
||||
$file_info = @{
|
||||
attributes = $dir_child.Attributes.ToString()
|
||||
checksum = $null
|
||||
creationtime = (New-TimeSpan -Start $epoch -End $dir_child.CreationTime).TotalSeconds
|
||||
exists = $true
|
||||
extension = $null
|
||||
filename = $dir_child.Name
|
||||
isarchive = $dir_child.Attributes.HasFlag([System.IO.FileAttributes]::Archive)
|
||||
isdir = $dir_child.Attributes.HasFlag([System.IO.FileAttributes]::Directory)
|
||||
ishidden = $dir_child.Attributes.HasFlag([System.IO.FileAttributes]::Hidden)
|
||||
isreadonly = $dir_child.Attributes.HasFlag([System.IO.FileAttributes]::ReadOnly)
|
||||
isreg = $false
|
||||
isshared = $false
|
||||
lastaccesstime = (New-TimeSpan -Start $epoch -End $dir_child.LastAccessTime).TotalSeconds
|
||||
lastwritetime = (New-TimeSpan -Start $epoch -End $dir_child.LastWriteTime).TotalSeconds
|
||||
owner = $null
|
||||
path = $dir_child.FullName
|
||||
sharename = $null
|
||||
size = $null
|
||||
}
|
||||
|
||||
try {
|
||||
$file_info.owner = $dir_child.GetAccessControl().Owner
|
||||
} catch {} # May not have rights to get the Owner, historical behaviour is to ignore.
|
||||
|
||||
if ($dir_child.Attributes.HasFlag([System.IO.FileAttributes]::Directory)) {
|
||||
$share_info = Get-CimInstance -ClassName Win32_Share -Filter "Path='$($dir_child.FullName -replace '\\', '\\')'"
|
||||
if ($null -ne $share_info) {
|
||||
$file_info.isshared = $true
|
||||
$file_info.sharename = $share_info.Name
|
||||
}
|
||||
} else {
|
||||
$file_info.extension = $dir_child.Extension
|
||||
$file_info.isreg = $true
|
||||
$file_info.size = $dir_child.Length
|
||||
|
||||
if ($GetChecksum) {
|
||||
try {
|
||||
$file_info.checksum = Get-FileChecksum -Path $dir_child.FullName -Algorithm $checksum_algorithm
|
||||
} catch {} # Just keep the checksum as $null in the case of a failure.
|
||||
}
|
||||
}
|
||||
|
||||
# Append the link information if the path is a link
|
||||
$link_info = @{
|
||||
isjunction = $false
|
||||
islnk = $false
|
||||
nlink = 1
|
||||
lnk_source = $null
|
||||
lnk_target = $null
|
||||
hlnk_targets = @()
|
||||
}
|
||||
$link_stat = Get-Link -link_path $dir_child.FullName
|
||||
if ($null -ne $link_stat) {
|
||||
switch ($link_stat.Type) {
|
||||
"SymbolicLink" {
|
||||
$link_info.islnk = $true
|
||||
$link_info.isreg = $false
|
||||
$link_info.lnk_source = $link_stat.AbsolutePath
|
||||
$link_info.lnk_target = $link_stat.TargetPath
|
||||
break
|
||||
}
|
||||
"JunctionPoint" {
|
||||
$link_info.isjunction = $true
|
||||
$link_info.isreg = $false
|
||||
$link_info.lnk_source = $link_stat.AbsolutePath
|
||||
$link_info.lnk_target = $link_stat.TargetPath
|
||||
break
|
||||
}
|
||||
"HardLink" {
|
||||
$link_info.nlink = $link_stat.HardTargets.Count
|
||||
|
||||
# remove current path from the targets
|
||||
$hlnk_targets = $link_info.HardTargets | Where-Object { $_ -ne $dir_child.FullName }
|
||||
$link_info.hlnk_targets = @($hlnk_targets)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($kv in $link_info.GetEnumerator()) {
|
||||
$file_info.$($kv.Key) = $kv.Value
|
||||
}
|
||||
|
||||
# Output the file_info object
|
||||
$file_info
|
||||
}
|
||||
}
|
||||
|
||||
$search_params = @{
|
||||
CheckedPaths = [System.Collections.Generic.HashSet`1[System.String]]@()
|
||||
GetChecksum = $get_checksum
|
||||
Module = $module
|
||||
FileType = $file_type
|
||||
Follow = $follow
|
||||
IsHidden = $hidden
|
||||
Recurse = $recurse
|
||||
}
|
||||
|
||||
if ($null -ne $age) {
|
||||
$seconds_per_unit = @{'s'=1; 'm'=60; 'h'=3600; 'd'=86400; 'w'=604800}
|
||||
$seconds_pattern = '^(-?\d+)(s|m|h|d|w)?$'
|
||||
$match = $age -match $seconds_pattern
|
||||
if ($Match) {
|
||||
$specified_seconds = [Int64]$Matches[1]
|
||||
if ($null -eq $Matches[2]) {
|
||||
$chosen_unit = 's'
|
||||
} else {
|
||||
$chosen_unit = $Matches[2]
|
||||
}
|
||||
|
||||
$total_seconds = $specified_seconds * ($seconds_per_unit.$chosen_unit)
|
||||
|
||||
if ($total_seconds -ge 0) {
|
||||
$search_params.Age = (Get-Date).AddSeconds($total_seconds * -1).Ticks
|
||||
} else {
|
||||
# Make sure we add the positive value of seconds to current time then make it negative for later comparisons.
|
||||
$age = (Get-Date).AddSeconds($total_seconds).Ticks
|
||||
$search_params.Age = $age * -1
|
||||
}
|
||||
$search_params.AgeStamp = $age_stamp
|
||||
} else {
|
||||
$module.FailJson("Invalid age pattern specified")
|
||||
}
|
||||
}
|
||||
|
||||
if ($null -ne $patterns) {
|
||||
$search_params.Patterns = $patterns
|
||||
$search_params.UseRegex = $use_regex
|
||||
}
|
||||
|
||||
if ($null -ne $size) {
|
||||
$bytes_per_unit = @{'b'=1; 'k'=1KB; 'm'=1MB; 'g'=1GB;'t'=1TB}
|
||||
$size_pattern = '^(-?\d+)(b|k|m|g|t)?$'
|
||||
$match = $size -match $size_pattern
|
||||
if ($Match) {
|
||||
$specified_size = [Int64]$Matches[1]
|
||||
if ($null -eq $Matches[2]) {
|
||||
$chosen_byte = 'b'
|
||||
} else {
|
||||
$chosen_byte = $Matches[2]
|
||||
}
|
||||
|
||||
$search_params.Size = $specified_size * ($bytes_per_unit.$chosen_byte)
|
||||
} else {
|
||||
$module.FailJson("Invalid size pattern specified")
|
||||
}
|
||||
}
|
||||
|
||||
$matched_files = foreach ($path in $paths) {
|
||||
# Ensure we pass in an absolute path. We use the ExecutionContext as this is based on the PSProvider path not the
|
||||
# process location which can be different.
|
||||
$abs_path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($path)
|
||||
Search-Path -Path $abs_path @search_params
|
||||
}
|
||||
|
||||
# Make sure we sort the files in alphabetical order.
|
||||
$module.Result.files = @() + ($matched_files | Sort-Object -Property {$_.path})
|
||||
|
||||
$module.ExitJson()
|
||||
|
|
@ -1,345 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2016, Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: win_find
|
||||
version_added: "2.3"
|
||||
short_description: Return a list of files based on specific criteria
|
||||
description:
|
||||
- Return a list of files based on specified criteria.
|
||||
- Multiple criteria are AND'd together.
|
||||
- For non-Windows targets, use the M(find) module instead.
|
||||
options:
|
||||
age:
|
||||
description:
|
||||
- Select files or folders whose age is equal to or greater than
|
||||
the specified time.
|
||||
- Use a negative age to find files equal to or less than
|
||||
the specified time.
|
||||
- You can choose seconds, minutes, hours, days or weeks
|
||||
by specifying the first letter of an of
|
||||
those words (e.g., "2s", "10d", 1w").
|
||||
type: str
|
||||
age_stamp:
|
||||
description:
|
||||
- Choose the file property against which we compare C(age).
|
||||
- The default attribute we compare with is the last modification time.
|
||||
type: str
|
||||
choices: [ atime, ctime, mtime ]
|
||||
default: mtime
|
||||
checksum_algorithm:
|
||||
description:
|
||||
- Algorithm to determine the checksum of a file.
|
||||
- Will throw an error if the host is unable to use specified algorithm.
|
||||
type: str
|
||||
choices: [ md5, sha1, sha256, sha384, sha512 ]
|
||||
default: sha1
|
||||
file_type:
|
||||
description: Type of file to search for.
|
||||
type: str
|
||||
choices: [ directory, file ]
|
||||
default: file
|
||||
follow:
|
||||
description:
|
||||
- Set this to C(yes) to follow symlinks in the path.
|
||||
- This needs to be used in conjunction with C(recurse).
|
||||
type: bool
|
||||
default: no
|
||||
get_checksum:
|
||||
description:
|
||||
- Whether to return a checksum of the file in the return info (default sha1),
|
||||
use C(checksum_algorithm) to change from the default.
|
||||
type: bool
|
||||
default: yes
|
||||
hidden:
|
||||
description: Set this to include hidden files or folders.
|
||||
type: bool
|
||||
default: no
|
||||
paths:
|
||||
description:
|
||||
- List of paths of directories to search for files or folders in.
|
||||
- This can be supplied as a single path or a list of paths.
|
||||
type: list
|
||||
required: yes
|
||||
patterns:
|
||||
description:
|
||||
- One or more (powershell or regex) patterns to compare filenames with.
|
||||
- The type of pattern matching is controlled by C(use_regex) option.
|
||||
- The patterns restrict the list of files or folders to be returned based on the filenames.
|
||||
- For a file to be matched it only has to match with one pattern in a list provided.
|
||||
type: list
|
||||
aliases: [ "regex", "regexp" ]
|
||||
recurse:
|
||||
description:
|
||||
- Will recursively descend into the directory looking for files or folders.
|
||||
type: bool
|
||||
default: no
|
||||
size:
|
||||
description:
|
||||
- Select files or folders whose size is equal to or greater than the specified size.
|
||||
- Use a negative value to find files equal to or less than the specified size.
|
||||
- You can specify the size with a suffix of the byte type i.e. kilo = k, mega = m...
|
||||
- Size is not evaluated for symbolic links.
|
||||
type: str
|
||||
use_regex:
|
||||
description:
|
||||
- Will set patterns to run as a regex check if set to C(yes).
|
||||
type: bool
|
||||
default: no
|
||||
author:
|
||||
- Jordan Borean (@jborean93)
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Find files in path
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
|
||||
- name: Find hidden files in path
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
hidden: yes
|
||||
|
||||
- name: Find files in multiple paths
|
||||
win_find:
|
||||
paths:
|
||||
- C:\Temp
|
||||
- D:\Temp
|
||||
|
||||
- name: Find files in directory while searching recursively
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
recurse: yes
|
||||
|
||||
- name: Find files in directory while following symlinks
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
recurse: yes
|
||||
follow: yes
|
||||
|
||||
- name: Find files with .log and .out extension using powershell wildcards
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
patterns: [ '*.log', '*.out' ]
|
||||
|
||||
- name: Find files in path based on regex pattern
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
patterns: out_\d{8}-\d{6}.log
|
||||
|
||||
- name: Find files older than 1 day
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
age: 86400
|
||||
|
||||
- name: Find files older than 1 day based on create time
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
age: 86400
|
||||
age_stamp: ctime
|
||||
|
||||
- name: Find files older than 1 day with unit syntax
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
age: 1d
|
||||
|
||||
- name: Find files newer than 1 hour
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
age: -3600
|
||||
|
||||
- name: Find files newer than 1 hour with unit syntax
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
age: -1h
|
||||
|
||||
- name: Find files larger than 1MB
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
size: 1048576
|
||||
|
||||
- name: Find files larger than 1GB with unit syntax
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
size: 1g
|
||||
|
||||
- name: Find files smaller than 1MB
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
size: -1048576
|
||||
|
||||
- name: Find files smaller than 1GB with unit syntax
|
||||
win_find:
|
||||
paths: D:\Temp
|
||||
size: -1g
|
||||
|
||||
- name: Find folders/symlinks in multiple paths
|
||||
win_find:
|
||||
paths:
|
||||
- C:\Temp
|
||||
- D:\Temp
|
||||
file_type: directory
|
||||
|
||||
- name: Find files and return SHA256 checksum of files found
|
||||
win_find:
|
||||
paths: C:\Temp
|
||||
get_checksum: yes
|
||||
checksum_algorithm: sha256
|
||||
|
||||
- name: Find files and do not return the checksum
|
||||
win_find:
|
||||
paths: C:\Temp
|
||||
get_checksum: no
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
examined:
|
||||
description: The number of files/folders that was checked.
|
||||
returned: always
|
||||
type: int
|
||||
sample: 10
|
||||
matched:
|
||||
description: The number of files/folders that match the criteria.
|
||||
returned: always
|
||||
type: int
|
||||
sample: 2
|
||||
files:
|
||||
description: Information on the files/folders that match the criteria returned as a list of dictionary elements
|
||||
for each file matched. The entries are sorted by the path value alphabetically.
|
||||
returned: success
|
||||
type: complex
|
||||
contains:
|
||||
attributes:
|
||||
description: attributes of the file at path in raw form.
|
||||
returned: success, path exists
|
||||
type: str
|
||||
sample: "Archive, Hidden"
|
||||
checksum:
|
||||
description: The checksum of a file based on checksum_algorithm specified.
|
||||
returned: success, path exists, path is a file, get_checksum == True
|
||||
type: str
|
||||
sample: 09cb79e8fc7453c84a07f644e441fd81623b7f98
|
||||
creationtime:
|
||||
description: The create time of the file represented in seconds since epoch.
|
||||
returned: success, path exists
|
||||
type: float
|
||||
sample: 1477984205.15
|
||||
exists:
|
||||
description: Whether the file exists, will always be true for M(win_find).
|
||||
returned: success, path exists
|
||||
type: bool
|
||||
sample: true
|
||||
extension:
|
||||
description: The extension of the file at path.
|
||||
returned: success, path exists, path is a file
|
||||
type: str
|
||||
sample: ".ps1"
|
||||
filename:
|
||||
description: The name of the file.
|
||||
returned: success, path exists
|
||||
type: str
|
||||
sample: temp
|
||||
hlnk_targets:
|
||||
description: List of other files pointing to the same file (hard links), excludes the current file.
|
||||
returned: success, path exists
|
||||
type: list
|
||||
sample:
|
||||
- C:\temp\file.txt
|
||||
- C:\Windows\update.log
|
||||
isarchive:
|
||||
description: If the path is ready for archiving or not.
|
||||
returned: success, path exists
|
||||
type: bool
|
||||
sample: true
|
||||
isdir:
|
||||
description: If the path is a directory or not.
|
||||
returned: success, path exists
|
||||
type: bool
|
||||
sample: true
|
||||
ishidden:
|
||||
description: If the path is hidden or not.
|
||||
returned: success, path exists
|
||||
type: bool
|
||||
sample: true
|
||||
isjunction:
|
||||
description: If the path is a junction point.
|
||||
returned: success, path exists
|
||||
type: bool
|
||||
sample: true
|
||||
islnk:
|
||||
description: If the path is a symbolic link.
|
||||
returned: success, path exists
|
||||
type: bool
|
||||
sample: true
|
||||
isreadonly:
|
||||
description: If the path is read only or not.
|
||||
returned: success, path exists
|
||||
type: bool
|
||||
sample: true
|
||||
isreg:
|
||||
description: If the path is a regular file or not.
|
||||
returned: success, path exists
|
||||
type: bool
|
||||
sample: true
|
||||
isshared:
|
||||
description: If the path is shared or not.
|
||||
returned: success, path exists
|
||||
type: bool
|
||||
sample: true
|
||||
lastaccesstime:
|
||||
description: The last access time of the file represented in seconds since epoch.
|
||||
returned: success, path exists
|
||||
type: float
|
||||
sample: 1477984205.15
|
||||
lastwritetime:
|
||||
description: The last modification time of the file represented in seconds since epoch.
|
||||
returned: success, path exists
|
||||
type: float
|
||||
sample: 1477984205.15
|
||||
lnk_source:
|
||||
description: The target of the symlink normalized for the remote filesystem.
|
||||
returned: success, path exists, path is a symbolic link or junction point
|
||||
type: str
|
||||
sample: C:\temp
|
||||
lnk_target:
|
||||
description: The target of the symlink. Note that relative paths remain relative, will return null if not a link.
|
||||
returned: success, path exists, path is a symbolic link or junction point
|
||||
type: str
|
||||
sample: temp
|
||||
nlink:
|
||||
description: Number of links to the file (hard links)
|
||||
returned: success, path exists
|
||||
type: int
|
||||
sample: 1
|
||||
owner:
|
||||
description: The owner of the file.
|
||||
returned: success, path exists
|
||||
type: str
|
||||
sample: BUILTIN\Administrators
|
||||
path:
|
||||
description: The full absolute path to the file.
|
||||
returned: success, path exists
|
||||
type: str
|
||||
sample: BUILTIN\Administrators
|
||||
sharename:
|
||||
description: The name of share if folder is shared.
|
||||
returned: success, path exists, path is a directory and isshared == True
|
||||
type: str
|
||||
sample: file-share
|
||||
size:
|
||||
description: The size in bytes of the file.
|
||||
returned: success, path exists, path is a file
|
||||
type: int
|
||||
sample: 1024
|
||||
'''
|
|
@ -1,200 +0,0 @@
|
|||
#!powershell
|
||||
|
||||
# Copyright: (c) 2019, Varun Chopra (@chopraaa) <v@chopraaa.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
#AnsibleRequires -CSharpUtil Ansible.Basic
|
||||
#AnsibleRequires -OSVersion 6.2
|
||||
|
||||
Set-StrictMode -Version 2
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$spec = @{
|
||||
options = @{
|
||||
drive_letter = @{ type = "str" }
|
||||
path = @{ type = "str" }
|
||||
label = @{ type = "str" }
|
||||
new_label = @{ type = "str" }
|
||||
file_system = @{ type = "str"; choices = "ntfs", "refs", "exfat", "fat32", "fat" }
|
||||
allocation_unit_size = @{ type = "int" }
|
||||
large_frs = @{ type = "bool" }
|
||||
full = @{ type = "bool"; default = $false }
|
||||
compress = @{ type = "bool" }
|
||||
integrity_streams = @{ type = "bool" }
|
||||
force = @{ type = "bool"; default = $false }
|
||||
}
|
||||
mutually_exclusive = @(
|
||||
,@('drive_letter', 'path', 'label')
|
||||
)
|
||||
required_one_of = @(
|
||||
,@('drive_letter', 'path', 'label')
|
||||
)
|
||||
supports_check_mode = $true
|
||||
}
|
||||
|
||||
$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
|
||||
|
||||
$drive_letter = $module.Params.drive_letter
|
||||
$path = $module.Params.path
|
||||
$label = $module.Params.label
|
||||
$new_label = $module.Params.new_label
|
||||
$file_system = $module.Params.file_system
|
||||
$allocation_unit_size = $module.Params.allocation_unit_size
|
||||
$large_frs = $module.Params.large_frs
|
||||
$full_format = $module.Params.full
|
||||
$compress_volume = $module.Params.compress
|
||||
$integrity_streams = $module.Params.integrity_streams
|
||||
$force_format = $module.Params.force
|
||||
|
||||
# Some pre-checks
|
||||
if ($null -ne $drive_letter -and $drive_letter -notmatch "^[a-zA-Z]$") {
|
||||
$module.FailJson("The parameter drive_letter should be a single character A-Z")
|
||||
}
|
||||
if ($integrity_streams -eq $true -and $file_system -ne "refs") {
|
||||
$module.FailJson("Integrity streams can be enabled only on ReFS volumes. You specified: $($file_system)")
|
||||
}
|
||||
if ($compress_volume -eq $true) {
|
||||
if ($file_system -eq "ntfs") {
|
||||
if ($null -ne $allocation_unit_size -and $allocation_unit_size -gt 4096) {
|
||||
$module.FailJson("NTFS compression is not supported for allocation unit sizes above 4096")
|
||||
}
|
||||
}
|
||||
else {
|
||||
$module.FailJson("Compression can be enabled only on NTFS volumes. You specified: $($file_system)")
|
||||
}
|
||||
}
|
||||
|
||||
function Get-AnsibleVolume {
|
||||
param(
|
||||
$DriveLetter,
|
||||
$Path,
|
||||
$Label
|
||||
)
|
||||
|
||||
if ($null -ne $DriveLetter) {
|
||||
try {
|
||||
$volume = Get-Volume -DriveLetter $DriveLetter
|
||||
} catch {
|
||||
$module.FailJson("There was an error retrieving the volume using drive_letter $($DriveLetter): $($_.Exception.Message)", $_)
|
||||
}
|
||||
}
|
||||
elseif ($null -ne $Path) {
|
||||
try {
|
||||
$volume = Get-Volume -Path $Path
|
||||
} catch {
|
||||
$module.FailJson("There was an error retrieving the volume using path $($Path): $($_.Exception.Message)", $_)
|
||||
}
|
||||
}
|
||||
elseif ($null -ne $Label) {
|
||||
try {
|
||||
$volume = Get-Volume -FileSystemLabel $Label
|
||||
} catch {
|
||||
$module.FailJson("There was an error retrieving the volume using label $($Label): $($_.Exception.Message)", $_)
|
||||
}
|
||||
}
|
||||
else {
|
||||
$module.FailJson("Unable to locate volume: drive_letter, path and label were not specified")
|
||||
}
|
||||
|
||||
return $volume
|
||||
}
|
||||
|
||||
function Format-AnsibleVolume {
|
||||
param(
|
||||
$Path,
|
||||
$Label,
|
||||
$FileSystem,
|
||||
$Full,
|
||||
$UseLargeFRS,
|
||||
$Compress,
|
||||
$SetIntegrityStreams,
|
||||
$AllocationUnitSize
|
||||
)
|
||||
$parameters = @{
|
||||
Path = $Path
|
||||
Full = $Full
|
||||
}
|
||||
if ($null -ne $UseLargeFRS) {
|
||||
$parameters.Add("UseLargeFRS", $UseLargeFRS)
|
||||
}
|
||||
if ($null -ne $SetIntegrityStreams) {
|
||||
$parameters.Add("SetIntegrityStreams", $SetIntegrityStreams)
|
||||
}
|
||||
if ($null -ne $Compress){
|
||||
$parameters.Add("Compress", $Compress)
|
||||
}
|
||||
if ($null -ne $Label) {
|
||||
$parameters.Add("NewFileSystemLabel", $Label)
|
||||
}
|
||||
if ($null -ne $FileSystem) {
|
||||
$parameters.Add("FileSystem", $FileSystem)
|
||||
}
|
||||
if ($null -ne $AllocationUnitSize) {
|
||||
$parameters.Add("AllocationUnitSize", $AllocationUnitSize)
|
||||
}
|
||||
|
||||
Format-Volume @parameters -Confirm:$false | Out-Null
|
||||
|
||||
}
|
||||
|
||||
$ansible_volume = Get-AnsibleVolume -DriveLetter $drive_letter -Path $path -Label $label
|
||||
$ansible_file_system = $ansible_volume.FileSystem
|
||||
$ansible_volume_size = $ansible_volume.Size
|
||||
$ansible_volume_alu = (Get-CimInstance -ClassName Win32_Volume -Filter "DeviceId = '$($ansible_volume.path.replace('\','\\'))'" -Property BlockSize).BlockSize
|
||||
|
||||
$ansible_partition = Get-Partition -Volume $ansible_volume
|
||||
|
||||
if (-not $force_format -and $null -ne $allocation_unit_size -and $ansible_volume_alu -ne 0 -and $null -ne $ansible_volume_alu -and $allocation_unit_size -ne $ansible_volume_alu) {
|
||||
$module.FailJson("Force format must be specified since target allocation unit size: $($allocation_unit_size) is different from the current allocation unit size of the volume: $($ansible_volume_alu)")
|
||||
}
|
||||
|
||||
foreach ($access_path in $ansible_partition.AccessPaths) {
|
||||
if ($access_path -ne $Path) {
|
||||
if ($null -ne $file_system -and
|
||||
-not [string]::IsNullOrEmpty($ansible_file_system) -and
|
||||
$file_system -ne $ansible_file_system)
|
||||
{
|
||||
if (-not $force_format)
|
||||
{
|
||||
$no_files_in_volume = (Get-ChildItem -LiteralPath $access_path -ErrorAction SilentlyContinue | Measure-Object).Count -eq 0
|
||||
if($no_files_in_volume)
|
||||
{
|
||||
$module.FailJson("Force format must be specified since target file system: $($file_system) is different from the current file system of the volume: $($ansible_file_system.ToLower())")
|
||||
}
|
||||
else
|
||||
{
|
||||
$module.FailJson("Force format must be specified to format non-pristine volumes")
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$pristine = -not $force_format
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($force_format) {
|
||||
if (-not $module.CheckMode) {
|
||||
Format-AnsibleVolume -Path $ansible_volume.Path -Full $full_format -Label $new_label -FileSystem $file_system -SetIntegrityStreams $integrity_streams -UseLargeFRS $large_frs -Compress $compress_volume -AllocationUnitSize $allocation_unit_size
|
||||
}
|
||||
$module.Result.changed = $true
|
||||
}
|
||||
else {
|
||||
if ($pristine) {
|
||||
if ($null -eq $new_label) {
|
||||
$new_label = $ansible_volume.FileSystemLabel
|
||||
}
|
||||
# Conditions for formatting
|
||||
if ($ansible_volume_size -eq 0 -or
|
||||
$ansible_volume.FileSystemLabel -ne $new_label) {
|
||||
if (-not $module.CheckMode) {
|
||||
Format-AnsibleVolume -Path $ansible_volume.Path -Full $full_format -Label $new_label -FileSystem $file_system -SetIntegrityStreams $integrity_streams -UseLargeFRS $large_frs -Compress $compress_volume -AllocationUnitSize $allocation_unit_size
|
||||
}
|
||||
$module.Result.changed = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$module.ExitJson()
|
|
@ -1,103 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2019, Varun Chopra (@chopraaa) <v@chopraaa.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
module: win_format
|
||||
version_added: '2.8'
|
||||
short_description: Formats an existing volume or a new volume on an existing partition on Windows
|
||||
description:
|
||||
- The M(win_format) module formats an existing volume or a new volume on an existing partition on Windows
|
||||
options:
|
||||
drive_letter:
|
||||
description:
|
||||
- Used to specify the drive letter of the volume to be formatted.
|
||||
type: str
|
||||
path:
|
||||
description:
|
||||
- Used to specify the path to the volume to be formatted.
|
||||
type: str
|
||||
label:
|
||||
description:
|
||||
- Used to specify the label of the volume to be formatted.
|
||||
type: str
|
||||
new_label:
|
||||
description:
|
||||
- Used to specify the new file system label of the formatted volume.
|
||||
type: str
|
||||
file_system:
|
||||
description:
|
||||
- Used to specify the file system to be used when formatting the target volume.
|
||||
type: str
|
||||
choices: [ ntfs, refs, exfat, fat32, fat ]
|
||||
allocation_unit_size:
|
||||
description:
|
||||
- Specifies the cluster size to use when formatting the volume.
|
||||
- If no cluster size is specified when you format a partition, defaults are selected based on
|
||||
the size of the partition.
|
||||
- This value must be a multiple of the physical sector size of the disk.
|
||||
type: int
|
||||
large_frs:
|
||||
description:
|
||||
- Specifies that large File Record System (FRS) should be used.
|
||||
type: bool
|
||||
compress:
|
||||
description:
|
||||
- Enable compression on the resulting NTFS volume.
|
||||
- NTFS compression is not supported where I(allocation_unit_size) is more than 4096.
|
||||
type: bool
|
||||
integrity_streams:
|
||||
description:
|
||||
- Enable integrity streams on the resulting ReFS volume.
|
||||
type: bool
|
||||
full:
|
||||
description:
|
||||
- A full format writes to every sector of the disk, takes much longer to perform than the
|
||||
default (quick) format, and is not recommended on storage that is thinly provisioned.
|
||||
- Specify C(true) for full format.
|
||||
type: bool
|
||||
force:
|
||||
description:
|
||||
- Specify if formatting should be forced for volumes that are not created from new partitions
|
||||
or if the source and target file system are different.
|
||||
type: bool
|
||||
notes:
|
||||
- Microsoft Windows Server 2012 or Microsoft Windows 8 or newer is required to use this module. To check if your system is compatible, see
|
||||
U(https://docs.microsoft.com/en-us/windows/desktop/sysinfo/operating-system-version).
|
||||
- One of three parameters (I(drive_letter), I(path) and I(label)) are mandatory to identify the target
|
||||
volume but more than one cannot be specified at the same time.
|
||||
- This module is idempotent if I(force) is not specified and file system labels remain preserved.
|
||||
- For more information, see U(https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/format-msft-volume)
|
||||
seealso:
|
||||
- module: win_disk_facts
|
||||
- module: win_partition
|
||||
author:
|
||||
- Varun Chopra (@chopraaa) <v@chopraaa.com>
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Create a partition with drive letter D and size 5 GiB
|
||||
win_partition:
|
||||
drive_letter: D
|
||||
partition_size: 5 GiB
|
||||
disk_number: 1
|
||||
|
||||
- name: Full format the newly created partition as NTFS and label it
|
||||
win_format:
|
||||
drive_letter: D
|
||||
file_system: NTFS
|
||||
new_label: Formatted
|
||||
full: True
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
#
|
||||
'''
|
|
@ -1,145 +0,0 @@
|
|||
#!powershell
|
||||
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
#Requires -Module Ansible.ModuleUtils.Legacy
|
||||
|
||||
Set-StrictMode -Version 2
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$system_path = "System\CurrentControlSet\Control\Session Manager\Environment"
|
||||
$user_path = "Environment"
|
||||
|
||||
# list/arraylist methods don't allow IEqualityComparer override for case/backslash/quote-insensitivity, roll our own search
|
||||
Function Get-IndexOfPathElement ($list, [string]$value) {
|
||||
$idx = 0
|
||||
$value = $value.Trim('"').Trim('\')
|
||||
ForEach($el in $list) {
|
||||
If ([string]$el.Trim('"').Trim('\') -ieq $value) {
|
||||
return $idx
|
||||
}
|
||||
|
||||
$idx++
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
# alters list in place, returns true if at least one element was added
|
||||
Function Add-Elements ($existing_elements, $elements_to_add) {
|
||||
$last_idx = -1
|
||||
$changed = $false
|
||||
|
||||
ForEach($el in $elements_to_add) {
|
||||
$idx = Get-IndexOfPathElement $existing_elements $el
|
||||
|
||||
# add missing elements at the end
|
||||
If ($idx -eq -1) {
|
||||
$last_idx = $existing_elements.Add($el)
|
||||
$changed = $true
|
||||
}
|
||||
ElseIf ($idx -lt $last_idx) {
|
||||
$existing_elements.RemoveAt($idx) | Out-Null
|
||||
$existing_elements.Add($el) | Out-Null
|
||||
$last_idx = $existing_elements.Count - 1
|
||||
$changed = $true
|
||||
}
|
||||
Else {
|
||||
$last_idx = $idx
|
||||
}
|
||||
}
|
||||
|
||||
return $changed
|
||||
}
|
||||
|
||||
# alters list in place, returns true if at least one element was removed
|
||||
Function Remove-Elements ($existing_elements, $elements_to_remove) {
|
||||
$count = $existing_elements.Count
|
||||
|
||||
ForEach($el in $elements_to_remove) {
|
||||
$idx = Get-IndexOfPathElement $existing_elements $el
|
||||
$result.removed_idx = $idx
|
||||
If ($idx -gt -1) {
|
||||
$existing_elements.RemoveAt($idx)
|
||||
}
|
||||
}
|
||||
|
||||
return $count -ne $existing_elements.Count
|
||||
}
|
||||
|
||||
# PS registry provider doesn't allow access to unexpanded REG_EXPAND_SZ; fall back to .NET
|
||||
Function Get-RawPathVar ($scope) {
|
||||
If ($scope -eq "user") {
|
||||
$env_key = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey($user_path)
|
||||
}
|
||||
ElseIf ($scope -eq "machine") {
|
||||
$env_key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($system_path)
|
||||
}
|
||||
|
||||
return $env_key.GetValue($var_name, "", [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
|
||||
}
|
||||
|
||||
Function Set-RawPathVar($path_value, $scope) {
|
||||
If ($scope -eq "user") {
|
||||
$var_path = "HKCU:\" + $user_path
|
||||
}
|
||||
ElseIf ($scope -eq "machine") {
|
||||
$var_path = "HKLM:\" + $system_path
|
||||
}
|
||||
|
||||
Set-ItemProperty $var_path -Name $var_name -Value $path_value -Type ExpandString | Out-Null
|
||||
|
||||
return $path_value
|
||||
}
|
||||
|
||||
$parsed_args = Parse-Args $args -supports_check_mode $true
|
||||
|
||||
$result = @{changed=$false}
|
||||
|
||||
$var_name = Get-AnsibleParam $parsed_args "name" -Default "PATH"
|
||||
$elements = Get-AnsibleParam $parsed_args "elements" -FailIfEmpty $result
|
||||
$state = Get-AnsibleParam $parsed_args "state" -Default "present" -ValidateSet "present","absent"
|
||||
$scope = Get-AnsibleParam $parsed_args "scope" -Default "machine" -ValidateSet "machine","user"
|
||||
|
||||
$check_mode = Get-AnsibleParam $parsed_args "_ansible_check_mode" -Default $false
|
||||
|
||||
If ($elements -is [string]) {
|
||||
$elements = @($elements)
|
||||
}
|
||||
|
||||
If ($elements -isnot [Array]) {
|
||||
Fail-Json $result "elements must be a string or list of path strings"
|
||||
}
|
||||
|
||||
$current_value = Get-RawPathVar $scope
|
||||
$result.path_value = $current_value
|
||||
|
||||
# TODO: test case-canonicalization on wacky unicode values (eg turkish i)
|
||||
# TODO: detect and warn/fail on unparseable path? (eg, unbalanced quotes, invalid path chars)
|
||||
# TODO: detect and warn/fail if system path and Powershell isn't on it?
|
||||
|
||||
$existing_elements = New-Object System.Collections.ArrayList
|
||||
|
||||
# split on semicolons, accounting for quoted values with embedded semicolons (which may or may not be wrapped in whitespace)
|
||||
$pathsplit_re = [regex] '((?<q>\s*"[^"]+"\s*)|(?<q>[^;]+))(;$|$|;)'
|
||||
|
||||
ForEach ($m in $pathsplit_re.Matches($current_value)) {
|
||||
$existing_elements.Add($m.Groups['q'].Value) | Out-Null
|
||||
}
|
||||
|
||||
If ($state -eq "absent") {
|
||||
$result.changed = Remove-Elements $existing_elements $elements
|
||||
}
|
||||
ElseIf ($state -eq "present") {
|
||||
$result.changed = Add-Elements $existing_elements $elements
|
||||
}
|
||||
|
||||
# calculate the new path value from the existing elements
|
||||
$path_value = [String]::Join(";", $existing_elements.ToArray())
|
||||
$result.path_value = $path_value
|
||||
|
||||
If ($result.changed -and -not $check_mode) {
|
||||
Set-RawPathVar $path_value $scope | Out-Null
|
||||
}
|
||||
|
||||
Exit-Json $result
|
|
@ -1,79 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2016, Red Hat | Ansible
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# This is a windows documentation stub. Actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'core'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: win_path
|
||||
version_added: "2.3"
|
||||
short_description: Manage Windows path environment variables
|
||||
description:
|
||||
- Allows element-based ordering, addition, and removal of Windows path environment variables.
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Target path environment variable name.
|
||||
type: str
|
||||
default: PATH
|
||||
elements:
|
||||
description:
|
||||
- A single path element, or a list of path elements (ie, directories) to add or remove.
|
||||
- When multiple elements are included in the list (and C(state) is C(present)), the elements are guaranteed to appear in the same relative order
|
||||
in the resultant path value.
|
||||
- Variable expansions (eg, C(%VARNAME%)) are allowed, and are stored unexpanded in the target path element.
|
||||
- Any existing path elements not mentioned in C(elements) are always preserved in their current order.
|
||||
- New path elements are appended to the path, and existing path elements may be moved closer to the end to satisfy the requested ordering.
|
||||
- Paths are compared in a case-insensitive fashion, and trailing backslashes are ignored for comparison purposes. However, note that trailing
|
||||
backslashes in YAML require quotes.
|
||||
type: list
|
||||
required: yes
|
||||
state:
|
||||
description:
|
||||
- Whether the path elements specified in C(elements) should be present or absent.
|
||||
type: str
|
||||
choices: [ absent, present ]
|
||||
scope:
|
||||
description:
|
||||
- The level at which the environment variable specified by C(name) should be managed (either for the current user or global machine scope).
|
||||
type: str
|
||||
choices: [ machine, user ]
|
||||
default: machine
|
||||
notes:
|
||||
- This module is for modifying individual elements of path-like
|
||||
environment variables. For general-purpose management of other
|
||||
environment vars, use the M(win_environment) module.
|
||||
- This module does not broadcast change events.
|
||||
This means that the minority of windows applications which can have
|
||||
their environment changed without restarting will not be notified and
|
||||
therefore will need restarting to pick up new environment settings.
|
||||
- User level environment variables will require an interactive user to
|
||||
log out and in again before they become available.
|
||||
seealso:
|
||||
- module: win_environment
|
||||
author:
|
||||
- Matt Davis (@nitzmahone)
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Ensure that system32 and Powershell are present on the global system path, and in the specified order
|
||||
win_path:
|
||||
elements:
|
||||
- '%SystemRoot%\system32'
|
||||
- '%SystemRoot%\system32\WindowsPowerShell\v1.0'
|
||||
|
||||
- name: Ensure that C:\Program Files\MyJavaThing is not on the current user's CLASSPATH
|
||||
win_path:
|
||||
name: CLASSPATH
|
||||
elements: C:\Program Files\MyJavaThing
|
||||
scope: user
|
||||
state: absent
|
||||
'''
|
|
@ -1,67 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2017, Dag Wieers <dag@wieers.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: win_tempfile
|
||||
version_added: "2.3"
|
||||
short_description: Creates temporary files and directories
|
||||
description:
|
||||
- Creates temporary files and directories.
|
||||
- For non-Windows targets, please use the M(tempfile) module instead.
|
||||
options:
|
||||
state:
|
||||
description:
|
||||
- Whether to create file or directory.
|
||||
type: str
|
||||
choices: [ directory, file ]
|
||||
default: file
|
||||
path:
|
||||
description:
|
||||
- Location where temporary file or directory should be created.
|
||||
- If path is not specified default system temporary directory (%TEMP%) will be used.
|
||||
type: path
|
||||
default: '%TEMP%'
|
||||
aliases: [ dest ]
|
||||
prefix:
|
||||
description:
|
||||
- Prefix of file/directory name created by module.
|
||||
type: str
|
||||
default: ansible.
|
||||
suffix:
|
||||
description:
|
||||
- Suffix of file/directory name created by module.
|
||||
type: str
|
||||
default: ''
|
||||
seealso:
|
||||
- module: tempfile
|
||||
author:
|
||||
- Dag Wieers (@dagwieers)
|
||||
'''
|
||||
|
||||
EXAMPLES = r"""
|
||||
- name: Create temporary build directory
|
||||
win_tempfile:
|
||||
state: directory
|
||||
suffix: build
|
||||
|
||||
- name: Create temporary file
|
||||
win_tempfile:
|
||||
state: file
|
||||
suffix: temp
|
||||
"""
|
||||
|
||||
RETURN = r'''
|
||||
path:
|
||||
description: The absolute path to the created file or directory.
|
||||
returned: success
|
||||
type: str
|
||||
sample: C:\Users\Administrator\AppData\Local\Temp\ansible.bMlvdk
|
||||
'''
|
|
@ -1,66 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# this is a virtual module that is entirely implemented server side
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['stableinterface'],
|
||||
'supported_by': 'core'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: win_template
|
||||
version_added: "1.9.2"
|
||||
short_description: Template a file out to a remote server
|
||||
options:
|
||||
backup:
|
||||
description:
|
||||
- Determine whether a backup should be created.
|
||||
- When set to C(yes), create a backup file including the timestamp information
|
||||
so you can get the original file back if you somehow clobbered it incorrectly.
|
||||
type: bool
|
||||
default: no
|
||||
version_added: '2.8'
|
||||
newline_sequence:
|
||||
default: '\r\n'
|
||||
force:
|
||||
version_added: '2.4'
|
||||
notes:
|
||||
- Beware fetching files from windows machines when creating templates because certain tools, such as Powershell ISE,
|
||||
and regedit's export facility add a Byte Order Mark as the first character of the file, which can cause tracebacks.
|
||||
- You can use the M(win_copy) module with the C(content:) option if you prefer the template inline, as part of the
|
||||
playbook.
|
||||
- For Linux you can use M(template) which uses '\\n' as C(newline_sequence) by default.
|
||||
seealso:
|
||||
- module: win_copy
|
||||
- module: copy
|
||||
- module: template
|
||||
author:
|
||||
- Jon Hawkesworth (@jhawkesworth)
|
||||
extends_documentation_fragment:
|
||||
- template_common
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Create a file from a Jinja2 template
|
||||
win_template:
|
||||
src: /mytemplates/file.conf.j2
|
||||
dest: C:\Temp\file.conf
|
||||
|
||||
- name: Create a Unix-style file from a Jinja2 template
|
||||
win_template:
|
||||
src: unix/config.conf.j2
|
||||
dest: C:\share\unix\config.conf
|
||||
newline_sequence: '\n'
|
||||
backup: yes
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
backup_file:
|
||||
description: Name of the backup file that was created.
|
||||
returned: if backup=yes
|
||||
type: str
|
||||
sample: C:\Path\To\File.txt.11540.20150212-220915.bak
|
||||
'''
|
Loading…
Reference in New Issue