Enabling or Disabling Windows Updates with SSM Run Command
AWS-ConfigureWindowsUpdate
When running the command, it downloads a PowerShell script to my EC2 at "C:\ProgramData\Amazon\Ec2Config\Downloads\aws_psModule\" with a random name
When the PowerShell script executes, it downloads "Amazon.ConfigureWindowsUpdate-1.2.zip" to "%Temp%" and then unzips it to "%WinDir%\System32\WindowsPowerShell\v1.0\Modules"
The script looks to be failing at Line 32 with the .CopyHere function where it is unzipping
Pastebin of Powershell Script: 1b3hh3oy.k51.ps1
(New-Object -Com Shell.Application).namespace($powerShellModuleLocation).CopyHere((New-Object -Com Shell.Application).namespace($tempLocation).Items(), 16)
Output:
Obtaining instance region from instance metadata.
Downloading ConfigureWindowsUpdate PowerShell module from S3.
Verifying SHA 256 of the ConfigureWindowsUpdate PowerShell module zip file.
ExtractingConfigureWindowsUpdate zip file contents to the Windows PowerShell module folder.
--------------ERROR-------------- C:\ProgramData\Amazon\Ec2Config\Downloads\aws_psModule\1b3hh3oy.k51.ps1 :
Exception thrown while downloading ConfigureWindowsUpdate
PowerShell module with message: Exception has been thrown by the target of an invocation.
At line:1 char:1
+ . 'C:\ProgramData\Amazon\Ec2Config\Downloads\aws_psModule\1b3hh3oy.k51.ps1' ; ex ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,1b3hh3oy.k51.ps1
Other Details:
- I have micro EC2 of Windows Server Core 2012 R2 running
- I have successfully used AWS-RunPowerShellScript command a few times from AWS Console
- I ran AWS-ConfigureWindowsUpdate through the AWS Console and it fails
- I remote connected to server and ran the powershell script with administrator privileges and get same error
You are correct, the exception is occurring on the call out to the Shell namespace for extracting the cmdlet payload. The COM namespace for Shell access is not included in the Core release so the ConfigureWindowsUpdate script fails when extracting the cmdlet.
Currently there is a workaround available for Windows Server Core AMIs and a more complete fix is currently being investigated. The workaround involves creating a custom ConfigureWindowsUpdate document with a tweak to fix the extraction process.
Below is a function that would replace the call to
(New-Object -Com Shell.Application).namespace($powerShellModuleLocation).CopyHere((New-Object -Com Shell.Application).namespace($tempLocation).Items(), 16)
function ExtractZipCoreOs($zipFilePath, $destPath) {
try
{
[System.Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") | Out-Null
$zip = [System.IO.Compression.ZipFile]::OpenRead($zipFilePath)
foreach ($item in $zip.Entries) {
$extractedPath = Join-Path $destPath $item.FullName
if ($item.Length -eq 0) {
if ((Test-Path $extractedPath) -eq 0) {
mkdir $extractedPath | Out-Null
}
} else {
$fileParent = Split-Path $extractedPath
if ((Test-Path $fileParent) -eq 0) {
mkdir $fileParent | Out-Null
}
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($item,(Join-Path -Path $powerShellModuleLocation -ChildPath $item.FullName), $true)
}
}
}
catch
{
throw "Error encountered when extracting ConfigureWindowsUpdate zip file.`n$($_.Exception.Message)"
}
finally
{
$zip.Dispose()
}
}
Related
I found this script for finding where msbuild.exe is, but it's not working. When I run it, it says "A parameter cannot be found that matches parameter name 'latest'" https://github.com/microsoft/vswhere/wiki/Find-MSBuild
Here is my script:
$path = %ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1
if ($path) {
& $path $args
}
Does anyone know what I'm doing wrong? I tried encapsulating the path in quotes, and putting it into a variable and tried using Invoke-Expression but this also did not work. In bash all I would need to do is encapsulate the command with ` and it would work.
Invoke-Expression -Command "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"
x86: The term 'x86' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
This also does not work
Try this, here I am expliclty creating a list of arguments in seperate strings.
$path = "$(${env:CommonProgramFiles(x86)})\Microsoft Visual Studio\Installer\vswhere.exe"
$args = "-latest", "-requires Microsoft.Component.MSBuild", "-find MSBuild\**\Bin\MSBuild.exe"
if ($path) {
Start-Process $path -ArgumentList $args
}
I am unable to test as i dont have Visual Studio.
This is "small" script which I wrote.
It will:
download latest recomended Nuget.exe in same directory where this PS script will be saved.
download/install "vswhere" nuget (in script directory)
will find latest "MSBuild.exe" path
$latestRecomendedUrl = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
$currentScriptDir = "$PSScriptRoot"
$nuget = Join-Path "$currentScriptDir" "nuget.exe"
if (!(Test-Path "$nuget" -pathType Leaf)) {
# download if not exists
Invoke-WebRequest "$latestRecomendedUrl" -OutFile "$nuget" | Out-Null
}
$vswhereExePartFromScriptDir = (Get-ChildItem -Path "$currentScriptDir" -Filter "vswhere.exe" -Recurse -Name)
$vswhereExe = Join-Path "$currentScriptDir" "$vswhereExePartFromScriptDir"
if ([string]::IsNullOrEmpty($vswhereExePartFromScriptDir)) {
try {
$args = "install", "-x", "-o", "$currentScriptDir", "vswhere"
&"$nuget" $args
Write-Host "Nuget was successfully downloaded."
}
finally {
$vswhereExePartFromScriptDir = (Get-ChildItem -Path "$currentScriptDir" -Filter "vswhere.exe" -Recurse -Name)
$vswhereExe = Join-Path "$currentScriptDir" "$vswhereExePartFromScriptDir"
# in my case install throws error #"nuget.exe : The requested operation cannot be performed on a file with a user-mapped section open."#
# but it download vswhere package successfully - so throw error only if it does not exist
if ([string]::IsNullOrEmpty($vswhereExePartFromScriptDir)) {
Write-Error "Failed to download 'vswhere.exe'."
}
else {
Write-Host "vswhere executable: ""$vswhereExe"""
}
}
}
else {
Write-Host "vswhere executable: ""$vswhereExe"""
}
$args = "-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild", "-find", "MSBuild\**\Bin\MSBuild.exe"
$msbuildExe = $(& "$vswhereExe" $args) | select-object -first 1
Write-Host "MSBuild exeutable: ""$msbuildExe"""
Output:
Feeds used:
https://api.nuget.org/v3/index.json
C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\
Installing package 'vswhere' to 'G:\scripts\ps'.
CACHE https://api.nuget.org/v3/registration5-gz-semver2/vswhere/index.json
Attempting to gather dependency information for package 'vswhere.3.1.1' with respect to project 'G:\scripts\ps', targeting 'Any, Version=
v0.0'
Gathering dependency information took 15 ms
Attempting to resolve dependencies for package 'vswhere.3.1.1' with DependencyBehavior 'Lowest'
Resolving dependency information took 0 ms
Resolving actions to install package 'vswhere.3.1.1'
Resolved actions to install package 'vswhere.3.1.1'
Retrieving package 'vswhere 3.1.1' from 'nuget.org'.
Adding package 'vswhere.3.1.1' to folder 'G:\scripts\ps'
WARNING: Install failed. Rolling back...
Executing nuget actions took 483 ms
nuget.exe : The requested operation cannot be performed on a file with a user-mapped section open.
At G:\scripts\ps\Get-MsBuildDir.ps1:21 char:9
+ &"$nuget" $args
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (The requested o...d section open.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
Nuget was successfully downloaded.
vswhere executable: "G:\scripts\ps\vswhere\tools\vswhere.exe"
MSBuild exeutable: "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe"
The problem is very easy to understand.
Yesterday I have installed en_visual_studio_2015_shell_isolated_x86_dvd_9fda4a05.iso and the file is hanging on my Desktop.
When I try to delete it through Remove-Item .\en_visual_studio_2015_shell_isolated_x86_dvd_9fda4a05.iso the Terminal fires back with the error:
Remove-Item : Cannot remove item C:\Users\franc\OneDrive\Desktop\en_visual_studio_2015_shell_isolated_x86_dvd_9fda4a05.iso: The process cannot access the file
'C:\Users\franc\OneDrive\Desktop\en_visual_studio_2015_shell_isolated_x86_dvd_9fda4a05.iso' because it is being used by another process.
At line:1 char:1
+ Remove-Item .\en_visual_studio_2015_shell_isolated_x86_dvd_9fda4a05.i ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (C:\Users\franc\...vd_9fda4a05.iso:FileInfo) [Remove-Item], IOException
+ FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
So I tried to find out what is handling that file:
$handleOut = handle
foreach ($line in $handleOut) {
if ($line -match '\S+\spid:') {
$exe = $line
}
elseif ($line -match 'C:\\Users\\franc\\OneDrive\\Desktop\\en_visual_studio_2015_shell_isolated_x86_dvd_9fda4a05.iso') {
"$exe - $line"
}
}
But the answer was:
System pid: 4 \<unable to open process> - 7540: File (R--) C:\Users\franc\OneDrive\Desktop\en_visual_studio_2015_shell_isolated_x86_dvd_9fda4a05.iso
System pid: 4 \<unable to open process> - 7B18: File (RW-) C:\Users\franc\OneDrive\Desktop\en_visual_studio_2015_shell_isolated_x86_dvd_9fda4a05.iso
I ultimately used Process Explorer and I found out that what is handling the file is OneDrive.
I stopped OneDrive but the problem persists.
Any suggestion?
This is sheerly speculation, but it sounds like you need to unmount the iso: https://www.digitalcitizen.life/mount-unmount-iso-file-explorer/
Have you tried running the command with the -Force parameter?
Remove-Item .\en_visual_studio_2015_shell_isolated_x86_dvd_9fda4a05.iso -Force
Does anyone have any idea why Remove-Item would fail while Delete works?
In below script, I get a list of files I'd like to delete.
Using Remove-Item I get following error message:
VERBOSE: Performing the operation "Remove File" on target
"\\UncPath\Folder\test.rtf". Remove-Item : Cannot remove item
\\UncPath\Folder\test.rtf: Access to the path is denied.
but using Delete is deleting those files as we speak.
Script
$files = gci \\UncPath\Folder| ?{ $_.LastWriteTime -le (Get-Date).addDays(-28) }
# This doesn't work
$files | Remove-Item -force -verbose
# But this does
$files | % { $_.Delete() }
powershell may act strange with UNC path, I think it prepends the UNC Path with the current provider you can verify this with :
cd c:
test-path \\127.0.0.1\c$
returns TRUE
cd HKCU:
test-path \\127.0.0.1\c$
returns FALSE
when specifying the fullpath we're telling powershell to use the filesystem provider, that solves the problem. you could also specify the provider like remove-item filesystem::\\uncpath\folder
I can finally repro this and IMO it appears to be a bug. The repro is to have an open share like C$ but to set Deny Modify perms for the user on the file. When I do that, I observe this:
PS> gci '\\Keith-PC\C$\Users\Keith\foo.txt' | ri -for
ri : Cannot remove item \\Keith-PC\C$\Users\Keith\foo.txt: Access to the path is denied.
At line:1 char:43
+ gci '\\Keith-PC\C$\Users\Keith\foo.txt' | ri -for
+ ~~~~~~~
+ CategoryInfo : InvalidArgument: (\\Keith-PC\C$\Users\Keith\foo.txt:FileInfo) [Remove-Item], ArgumentExc
eption
+ FullyQualifiedErrorId : RemoveFileSystemItemArgumentError,Microsoft.PowerShell.Commands.RemoveItemCommand
PS> gci '\\Keith-PC\C$\Users\Keith\foo.txt' | %{$_.Delete()} # <== this works!
I also observe that removing the -Force parameter deletes the file without error as well. The deny perms still allow me to delete the file from Windows Explorer so that leads me to believe that the file should delete. So what is up with using the -Force parameter? When I delve into the ErrorRecord I see this:
Message : Access to the path is denied.
ParamName :
Data : {}
InnerException :
TargetSite : Void set_Attributes(System.IO.FileAttributes)
StackTrace : at System.IO.FileSystemInfo.set_Attributes(FileAttributes value)
at Microsoft.PowerShell.Commands.FileSystemProvider.RemoveFileSystemItem(FileSystemInfo
fileSystemInfo, Boolean force)
It seems that the -Force parameter is trying to set (more likely reset) attributes and the permissions on the file don't allow it e.g.:
PS> gci '\\Keith-PC\C$\Users\Keith\foo.txt' | %{$_.Attributes = 'Normal'}
Exception setting "Attributes": "Access to the path is denied."
At line:1 char:45
+ gci '\\Keith-PC\C$\Users\Keith\foo.txt' | %{$_.Attributes = 'Normal'}
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
So it seems to me that PowerShell should first try as if the -Force weren't present and if that fails, then try resetting attributes.
I'm trying to load sharepoint script from *.cmd file.
I have Sharepoint 2010 installed on Windows 7 x64 and SQL server 2008r2.
My cmd file is:
Powershell -v 2 -NonInteractive -NoLogo -File 1.ps1
My sharepoint file 1.ps1 is:
$snapin="Microsoft.SharePoint.PowerShell"
if ($action -eq $null -or $action -eq '')
{<br />
# Action by default is complete uninstallation.
$action='uninstall'
$uninstall = $true
}
else
{
$action = $action.ToLower()
switch($action)
{
{ $_ -eq "uninstall" } { $uninstall = $true; break }
{ $_ -eq "removesolution" } { $removeSolution = $true; break }
{ $_ -eq "deactivatecorpus" } { $deactivateCorpus = $true; break }
{ $_ -eq "deactivatesupport" } { $deactivateSupport = $true; break }
default { Write-Host -f Red "Error: Invalid action: $action "; Exit -1 }
}
}
Check the Sharepoint snapin availability.
if (Get-PSSnapin $snapin -ea "silentlycontinue")
{
Write-Host "PS snapin $snapin is loaded."
}
elseif (Get-PSSnapin $snapin -registered -ea "silentlycontinue")
{
Write-Host "PS snapin $snapin is registered."
Add-PSSnapin $snapin
Write-Host "PS snapin $snapin is loaded."
}
else
{
Write-Host -f Red "Error: PS snapin $snapin is not found."
Exit -1
}
$url = "http:///sites/GroupWork/"
$site= new-Object Microsoft.SharePoint.SPSite($url )
$loc= [System.Int32]::Parse(1033)
$templates= $site.GetWebTemplates($loc)
foreach ($child in $templates){ write-host $child.Name " " $child.Title}<br />
$site.Dispose()
The script works fine from the Sharepoint 2010 management shell after launching the shell from the start menu (or from windows cmd by entering powershell -v 2):
PS C:\2> .\1.ps1
PS snapin Microsoft.SharePoint.PowerShell is loaded.
GLOBAL#0 Global template
STS#0 Team Site
STS#1 Blank Site
STS#2 Document Workspace
MPS#0 Basic Meeting Workspace
MPS#1 Blank Meeting Workspace
MPS#2 Decision Meeting Workspace
MPS#3 Social Meeting Workspace
MPS#4 Multipage Meeting Workspace
CENTRALADMIN#0 Central Admin Site
WIKI#0 Wiki Site
BLOG#0 Blog
SGS#0 Group Work Site
TENANTADMIN#0 Tenant Admin Site
{248A640A-AE86-42B7-90EC-45EC8618D6B4}#MySite2 MySite2
{95629DC2-03B1-4C92-AD70-BC1FEAA49E7D}#MySite1 MySite1
{7F01CFE4-F5E2-408B-AC87-E186D21F624C}#NewSiteTemplate NewSiteTemplate
PS C:\2>
I have an access to the database Sharepoint_Config from current domain user and from other 2 users. All users have db_owner rights to the Sharepoint_Config database.
But i've loaded in windows from the user which is dbo in the database (dbo with windows authentication with domain\username for the current user). The dbo user has do_owner rights in the Sharepoint_Config database.
I've tried to login under other users and launch the cmd file but without success.
My PowerShell has version 2.0:
PS C:\2> $psversiontable
Name Value
---- -----
CLRVersion 2.0.50727.5477
BuildVersion 6.1.7601.17514
PSVersion 2.0
WSManStackVersion 2.0
PSCompatibleVersions {1.0, 2.0}
SerializationVersion 1.1.0.1
PSRemotingProtocolVersion 2.1
After launching the script from 1.cmd file i get an errors:
C:\2>Powershell -v 2 -NonInteractive -NoLogo -File 1.ps1
PS snapin Microsoft.SharePoint.PowerShell is registered.
The local farm is not accessible. Cmdlets with FeatureDependencyId are not regis
tered.
Could not read the XML Configuration file in the folder CONFIG\PowerShell\Regist
ration.
Could not find a part of the path 'C:\2\CONFIG\PowerShell\Registration'.
No xml configuration files loaded.
Unable to register core product cmdlets.
Could not read the Types files in the folder CONFIG\PowerShell\types.
Could not find a part of the path 'C:\2\CONFIG\PowerShell\types'.
"No Types files Found."
Could not read the Format file in the folder CONFIG\PowerShell\format.
Could not find a part of the path 'C:\2\CONFIG\PowerShell\format'.
No Format files Found.
PS snapin Microsoft.SharePoint.PowerShell is loaded.
New-Object : Exception calling ".ctor" with "1" argument(s): "The Web applicati
on at
http://Pc1/sites/GroupWork/ could not be found. Verify t
hat you have typed the URL correctly. If the URL should be serving existing con
tent, the system administrator may need to add a new request URL mapping to the
intended application."
At C:\2\1.ps1:48 char:18
+ $site= new-Object <<<< Microsoft.SharePoint.SPSite($url )
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvoca
tionException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.Power
Shell.Commands.NewObjectCommand
I don't understand why the script is launched from the sharepoint management shell but doesn't work from the cmd file.
So we are using PsExec a lot in our automations to install virtual machines, as we can't use ps remote sessions with our windows 2003 machines. Everything works great and there are no Problems, but PsExec keeps throwing errors, even every command is being carried out without correctly.
For example:
D:\tools\pstools\psexec.exe $guestIP -u $global:default_user -p $global:default_pwd -d -i C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command "Enable-PSRemoting -Force"
Enables the PsRemoting on the guest, but also throws this error message:
psexec.exe :
Bei D:\Scripts\VMware\VMware_Module5.ps1:489 Zeichen:29
+ D:\tools\pstools\psexec.exe <<<< $guestIP -u $global:default_user -p $global:default_pwd -d -i C:\Windows\System32\WindowsPowerShell\
v1.0\powershell.exe -command "Enable-PSRemoting -Force"
+ CategoryInfo : NotSpecified: (:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
PsExec v1.98 - Execute processes remotely
Copyright (C) 2001-2010 Mark Russinovich
Sysinternals - www.sysinternals.com
Connecting to 172.17.23.95...Starting PsExec service on 172.17.23.95...Connecting with PsExec service on 172.17.23.95...Starting C:\Windows\
System32\WindowsPowerShell\v1.0\powershell.exe on 172.17.23.95...
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe started on 172.17.23.95 with process ID 2600.
These kinds of error messages apear ALWAYS no matter how i use psexec, like with quotes, with vriables/fixed values, other flags, etc. Does anybody has an idea how i could fix this? It is not a real problem, but it makes finding errors a pain in the ass, because the "errors" are everywhere. Disabling the error messages of psexec at all would also help...
This is because PowerShell sometimes reports a NativeCommandError when a process writes to STDERR. PsExec writes the infoline
PsExec v1.98 - Execute processes remotely
Copyright (C) 2001-2010 Mark Russinovich
Sysinternals - www.sysinternals.com
to STDERR which means it can cause this.
For more information, see these questions / answers:
https://stackoverflow.com/a/1416933/478656
https://stackoverflow.com/a/11826589/478656
https://stackoverflow.com/a/10666208/478656
redirect stderr to null worked best for me. see below link
Error when calling 3rd party executable from Powershell when using an IDE
Here's the relevant section from that link:
To avoid this you can redirect stderr to null e.g.:
du 2> $null
Essentially the console host and ISE (as well as remoting) treat the stderr stream differently. On the console host it was important for PowerShell to support applications like edit.com to work along with other applications that write colored output and errors to the screen. If the I/O stream is not redirected on console host, PowerShell gives the native EXE a console handle to write to directly. This bypasses PowerShell so PowerShell can't see that there are errors written so it can't report the error via $error or by writing to PowerShell's stderr stream.
ISE and remoting don't need to support this scenario so they do see the errors on stderr and subsequently write the error and update $error.
.\PsExec.exe \$hostname -u $script:userName -p $script:password /accepteula -h cmd /c $powerShellArgs 2> $null
I have created a psexec wrapper for powershell, which may be helpful to people browsing this question:
function Return-CommandResultsUsingPsexec {
param(
[Parameter(Mandatory=$true)] [string] $command_str,
[Parameter(Mandatory=$true)] [string] $remote_computer,
[Parameter(Mandatory=$true)] [string] $psexec_path,
[switch] $include_blank_lines
)
begin {
$remote_computer_regex_escaped = [regex]::Escape($remote_computer)
# $ps_exec_header = "`r`nPsExec v2.2 - Execute processes remotely`r`nCopyright (C) 2001-2016 Mark Russinovich`r`nSysinternals - www.sysinternals.com`r`n"
$ps_exec_regex_headers_array = #(
'^\s*PsExec v\d+(?:\.\d+)? - Execute processes remotely\s*$',
'^\s*Copyright \(C\) \d{4}(?:-\d{4})? Mark Russinovich\s*$',
'^\s*Sysinternals - www\.sysinternals\.com\s*$'
)
$ps_exec_regex_info_array = #(
('^\s*Connecting to ' + $remote_computer_regex_escaped + '\.{3}\s*$'),
('^\s*Starting PSEXESVC service on ' + $remote_computer_regex_escaped + '\.{3}\s*$'),
('^\s*Connecting with PsExec service on ' + $remote_computer_regex_escaped + '\.{3}\s*$'),
('^\s*Starting .+ on ' + $remote_computer_regex_escaped + '\.{3}\s*$')
)
$bypass_regex_array = $ps_exec_regex_headers_array + $ps_exec_regex_info_array
$exit_code_regex_str = ('^.+ exited on ' + $remote_computer_regex_escaped + ' with error code (\d+)\.\s*$')
$ps_exec_args_str = ('"\\' + $remote_computer + '" ' + $command_str)
}
process {
$return_dict = #{
'std_out' = (New-Object 'system.collections.generic.list[string]');
'std_err' = (New-Object 'system.collections.generic.list[string]');
'exit_code' = $null;
'bypassed_std' = (New-Object 'system.collections.generic.list[string]');
}
$process_info = New-Object System.Diagnostics.ProcessStartInfo
$process_info.RedirectStandardError = $true
$process_info.RedirectStandardOutput = $true
$process_info.UseShellExecute = $false
$process_info.FileName = $psexec_path
$process_info.Arguments = $ps_exec_args_str
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $process_info
$process.Start() | Out-Null
$std_dict = [ordered] #{
'std_out' = New-Object 'system.collections.generic.list[string]';
'std_err' = New-Object 'system.collections.generic.list[string]';
}
# $stdout_str = $process.StandardOutput.ReadToEnd()
while ($true) {
$line = $process.StandardOutput.ReadLine()
if ($line -eq $null) {
break
}
$std_dict['std_out'].Add($line)
}
# $stderr_str = $process.StandardError.ReadToEnd()
while ($true) {
$line = $process.StandardError.ReadLine()
if ($line -eq $null) {
break
}
$std_dict['std_err'].Add($line)
}
$process.WaitForExit()
ForEach ($std_type in $std_dict.Keys) {
ForEach ($line in $std_dict[$std_type]) {
if ((-not $include_blank_lines) -and ($line -match '^\s*$')) {
continue
}
$do_continue = $false
ForEach ($regex_str in $bypass_regex_array) {
if ($line -match $regex_str) {
$return_dict['bypassed_std'].Add($line)
$do_continue = $true
break
}
}
if ($do_continue) {
continue
}
$exit_code_regex_match = [regex]::Match($line, $exit_code_regex_str)
if ($exit_code_regex_match.Success) {
$return_dict['exit_code'] = [int] $exit_code_regex_match.Groups[1].Value
} elseif ($std_type -eq 'std_out') {
$return_dict['std_out'].Add($line)
} elseif ($std_type -eq 'std_err') {
$return_dict['std_err'].Add($line)
} else {
throw 'this conditional should never be true; if so, something was coded incorrectly'
}
}
}
return $return_dict
}
}