Jump to content

Problem with AutoIt, Powershell and WSUS


 Share

Recommended Posts

Hello!

First, sorry for bad English, but i am German. Now, the Problem i have:

I tried to write a program with a GUI to Approve Updates on a WSUS-Server quicker than 5 clicks for an update (gets annoying to approve ~30 Updates for ~10 Computer-Groups). Therefore, I have a gui listing all available updates and each update has a Checkbox. There also exists a Combo box where the Target Group can be chosen.

I wrote two powershell-scripts to read all the Target-Groups and available updates in inifiles. Those scripts work - if i run them using powershell only. When i run the powershell script from my AutiIt-Program, i get a WsusInvalidServerException.

Here are the lines which call the scripts:

;this inifile is needed to create the dropdown

ShellExecuteWait("powershell.exe", ' -ExecutionPolicy ByPass -noexit ' & @ScriptDir & '\GroupRead.ps1 -FilePath ' & $sGroupIni, @ScriptDir)

;create the inifile with all the updates

ShellExecuteWait("powershell.exe", ' -ExecutionPolicy ByPass -noexit ' & @ScriptDir & '\UpdateRead.ps1 -FilePath ' & $sUpdatIni, @ScriptDir)

You may wonder about the parameters, but this even works, too. Those are to set the paths for the created inifiles, and the files are created at those paths (and at the default paths when i didn´t have this Parameters).

And here are the powershell-scripts (those ones work and create the Ini-files like I need them):

GroupRead.ps1

 

param([string]$FilePath = $env:temp + '\' + $(Get-WmiObject Win32_Computersystem).name + '-GroupList.ini')


[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") 


$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer()

$groups = $wsus.GetComputerTargetGroups()

$count = 0

Write-Output "[UpdateGroups]" | Out-File -FilePath $FilePath

$groups | ForEach-Object {

$grstring = $_.Name

Write-Output $null"group"$count"="$grstring | Out-File -FilePath $FilePath -Append

$count ++

}

UpdateRead.PS1

 

param([string]$FilePath = $env:temp + '\' + $(Get-WmiObject Win32_Computersystem).name + '-UpdateList.ini')

 

$updateList = Get-WsusUpdate -Approval Unapproved | Select-Object UpdateID, UpdatesSupersededByThisUpdate, Classification

 

#show the updatelist in the console

$updateList

#create a file in the post-dir

 

Write-Output $updateList | Out-File -FilePath $FilePath

#try 2

$counter = 0

$updateList | foreach-object {

$uid = $_.UpdateID.ToString()

$uname1 = $_.UpdatesSupersededByThisUpdate

$uname2 = $_.UpdatesSupersedingThisUpdate

Write-Output "[$counter]" "updateid=$uid" "name1=$uname1" "name2=$uname2" | Out-File -FilePath $FilePath -Append

$counter++

}

#cleaning all variables

$updateList = $null

And there is another problem with this line:

ShellExecuteWait("powershell.exe", "Get-WsusUpdate -UpdateID " & IniRead($sUpdatIni, $aUpdateDatabase[$iCount], 'updateid', "default") & " | Approve-WsusUpdate -Action Install -TargetGroupName " & $sGroup)

Here i´d like to approve an update, the line gets the correct parameters but i also get the same exception. I created the inifiles with the powershell-scripts and commented the lines in my AutoIt-Script that it does not overwrite them.

This is my first bigger program, and i am new to AutoIt and Powershell, and i am very sure ist just a very small thing i forgot. It only seems to have Problems with the CMDLets for the WSUS-Server, everything else works. Hope somebody can help me.

Edited by 25x14
Link to comment
Share on other sites

  • Moderators

So if you do something like this:

ConsoleWrite("powershell.exe Get-WsusUpdate -UpdateID " & IniRead($sUpdatIni, $aUpdateDatabase[$iCount], 'updateid', "default") & " | Approve-WsusUpdate -Action Install -TargetGroupName " & $sGroup & @CRLF)

does the output print the command line as you would expect it to look?

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

Link to comment
Share on other sites

Welcome to the AutoIt forum 25x14! :)

Using code tags can help out with syntax highlighting a box with scrolling for easy readability. This can be done with the blue A in the toolbar and selecting the language you want to use.

Like so:

Global $var = "Test" ; this is a test

 

Posts can be easily edited at the bottom right of each of your post.  ^_^

Snips & Scripts


My Snips: graphCPUTemp ~ getENVvars
My Scripts: Short-Order Encrypter - message and file encryption V1.6.1 ~ AuPad - Notepad written entirely in AutoIt V1.9.4

Feel free to use any of my code for your own use.                                                                                                                                                           Forum FAQ

 

Link to comment
Share on other sites

So if you do something like this:

ConsoleWrite("powershell.exe Get-WsusUpdate -UpdateID " & IniRead($sUpdatIni, $aUpdateDatabase[$iCount], 'updateid', "default") & " | Approve-WsusUpdate -Action Install -TargetGroupName " & $sGroup & @CRLF)

does the output print the command line as you would expect it to look?

Thanks for the fast reply! I didn´t use ConsoleWrite, i tested it with a message box, there it looked like i expected it. The Output in the powershell itself again, is the same exception (Invalid WSUS-Server), but typing everything in the powershell-console, it worked.

Link to comment
Share on other sites

Welcome to the AutoIt forum 25x14! :)

Using code tags can help out with syntax highlighting a box with scrolling for easy readability. This can be done with the blue A in the toolbar and selecting the language you want to use.

Like so:

Global $var = "Test" ; this is a test

Posts can be easily edited at the bottom right of each of your post.  ^_^

Thanks for the hint :-)

Its very strange, i can only edit my own replies but not the first post

Link to comment
Share on other sites

Thanks for the hint :-)

Its very strange, i can only edit my own replies but not the first post

Anytime. :)

That is weird. I would try after you have 10 posts. Could be a limit set on new accounts.

Snips & Scripts


My Snips: graphCPUTemp ~ getENVvars
My Scripts: Short-Order Encrypter - message and file encryption V1.6.1 ~ AuPad - Notepad written entirely in AutoIt V1.9.4

Feel free to use any of my code for your own use.                                                                                                                                                           Forum FAQ

 

Link to comment
Share on other sites

for cmdlets with AD i have to load that module in session each time, maybe it is the same for WSUS?   What is the output of get-module

wait...disregard.  Mine reflects correctly but still requires that when i run 'powershell -command' from autoit, that i first run 'import-module ActiveDirectory' prior to things like get-aduser.  Maybe in the same vein you would need to do a  'Install-WindowsFeature -Name UpdateServices-RSAT' in session.  see my syntax:

though i also abandoned .ps1 files and directly run from the cli

Edited by boththose

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Link to comment
Share on other sites

for cmdlets with AD i have to load that module in session each time, maybe it is the same for WSUS?   What is the output of get-module

wait...disregard.  Mine reflects correctly but still requires that when i run 'powershell -command' from autoit, that i first run 'import-module ActiveDirectory' prior to things like get-aduser.  Maybe in the same vein you would need to do a  'Install-WindowsFeature -Name UpdateServices-RSAT' in session.  see my syntax:

though i also abandoned .ps1 files and directly run from the cli

 

Now thats how the "new" syntax looks like (I don´t know why the code editor doesn´t format the colors)

I also tried it without the -command and also with -command -noexit (i wanted to see if it displays an error)

$sCommands = "powershell -Command Get-WsusUpdate -UpdateID " & IniRead($sUpdatIni, $aUpdateDatabase[$iCount], 'updateid', "default") & " | Approve-WsusUpdate -Action Install -TargetGroupName " & $sGroup
    $iPID = Run(@ComSpec & " /c " & $sCommands, "", @SW_SHOW , $stdout_child)
    $sOutput = ""

    While 1
        $sOutput &= StdoutRead($iPID)
        If @error Then ; Exit the loop if the process closes or StderrRead returns an error.
            ExitLoop
        EndIf
    WEnd

Also i didn´t find any module which Needs to be includet to use powershell with WSUS. BTW, here is what i include:

#include <GUIConstants.au3>
#include <GUIConstantsEX.au3>
#include <EditConstants.au3>
#include <File.au3>
#include <Array.au3>
#include <IE.au3>
#include <WindowsConstants.au3>
#include <ProgressConstants.au3>
#include <ComboConstants.au3>
#include <GuiButton.au3>
#include <StaticConstants.au3>
#include <Constants.au3>
#include <general_options.au3>

Maybe there is something missing to run powershell, or there is something that doesn´t work with powershell and WSUS?

Link to comment
Share on other sites

I also tried to get the most important part working:

;this inifile is needed to create the dropdown-menue for the groups
ShellExecuteWait("powershell.exe", ' -ExecutionPolicy ByPass -noexit ' & @ScriptDir & '\GroupRead.ps1 -FilePath ' & $sGroupIni, @ScriptDir)

;create the inifile with all the updates
ShellExecuteWait("powershell.exe", ' -ExecutionPolicy ByPass -noexit ' & @ScriptDir & '\UpdateRead.ps1 -FilePath ' & $sUpdatIni, @ScriptDir)

The console starts, is ran as Administrator and by using the -noexit it displays the exception

Edited by 25x14
Link to comment
Share on other sites

Is it possible because i compile the program on a Windows 7 machine but run it on a server? Seems only to have problems with the "UpdateServices"-module in powershell, and with the following line from GroupRead.ps1:

$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer()

I also tried to Import the module "UpdateServices" on both powershell-scripts.

Here is an important part, how i handle the scripts

Func _createFiles()
    ;reading the groups and writing them in an inifile
    FileInstall("Scripts\GroupRead.ps1", @ScriptDir & '\GroupRead.ps1', 1)
    ;same as GroupRead, just for all the available Updates
    FileInstall("Scripts\UpdateRead.ps1", @ScriptDir & '\UpdateRead.ps1', 1)
    ;tried to start the programs above as administrator
    FileInstall("Scripts\Starter.ps1", @ScriptDir & '\Starter.ps1', 1)
EndFunc   ;==>_createFiles





Func _deleteFiles()
    FileDelete(@ScriptDir & '\GroupRead.ps1')
    FileDelete(@ScriptDir & '\UpdateRead.ps1')
    FileDelete(@ScriptDir & '\Starter.ps1')
EndFunc   ;==>_deleteFiles

These functions also work. Please ignore the Starter.ps1, it was another try that didn´t work. Had the same failure i tried to start the two scripts with an external file to make sure it is run by the Admin.

Link to comment
Share on other sites

Also i didn´t find any module which Needs to be includet to use powershell with WSUS. BTW, here is what i include:

 

im talking Windows OS features, see here:

http://www.powershellmagazine.com/2012/11/07/client-and-patch-management-using-the-updateservices-module/

The mechanism by which they are adding the WSUS stuff for powershell is the exact same way you have to add them for AD.  However, when you run commands that use that feature from outside powershell, you must explicitly call it.  Which is why all of  my AD commands are really two commands and look like:

powershell -Command import-module ActiveDirectory; "Get-ADComputer -Filter *

Eventhough I already have the feature added, and the Get-ADComputer command would work fine by itself in Powershell.

edit:  If I did not add that 'import-module ActiveDirectory' first, I would throw an exception on the Get-ADComputer command, which is what makes me think the issues may be related.

 

Edited by boththose

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Link to comment
Share on other sites

im talking Windows OS features, see here:

http://www.powershellmagazine.com/2012/11/07/client-and-patch-management-using-the-updateservices-module/

The mechanism by which they are adding the WSUS stuff for powershell is the exact same way you have to add them for AD.  However, when you run commands that use that feature from outside powershell, you must explicitly call it.  Which is why all of  my AD commands are really two commands and look like:

powershell -Command import-module ActiveDirectory; "Get-ADComputer -Filter *

Eventhough I already have the feature added, and the Get-ADComputer command would work fine by itself in Powershell.

edit:  If I did not add that 'import-module ActiveDirectory' first, I would throw an exception on the Get-ADComputer command, which is what makes me think the issues may be related.

 

Thanks for the hint, but now i have the Problem that i do something wrong.

This is what i have now, using your Syntax and trying to edit it for my script

$sCommands = 'powershell import-module UpdateServices; "Invoke-Expression & ' & @ScriptDir & '\GroupRead.ps1 -ExecutionPolicy ByPass -FilePath ' & $sGroupIni & '"'
_LogComment("C:\output.txt", $sCommands)
$iPID = RunWait(@ComSpec & " /c " & $sCommands, "", @SW_SHOW , $stdout_child)

_LogComment is a function for logfiles, in this case i used it to create an Output.

This is what the output says. For the post i modified the path, but be sure it is correct ;-):

powershell import-module UpdateServices; "Invoke-Expression & Drive:\*script*\GroupRead.ps1 -ExecutionPolicy ByPass -FilePath Drive:\*script*\Groups.ini"

Now it doesn´t even call the script so I am sure i have the mistake at the Invoce-Expression. I hope i can use RunWait in this case because when it works, the inifile Needs to be complete before the program continues. The next command will immediately read the file.

 

EDIT:

This is the other part where i want to approve the updates:

$sCommands = 'powershell import-module UpdateServices; "Get-WsusUpdate -UpdateID ' & IniRead($sUpdatIni, $aUpdateDatabase[$iCount], "updateid", "default") & ' | Approve-WsusUpdate -Action Install -TargetGroupName ' & $sGroup & '"'
_LogComment($sDateName, $sCommands)
_LogMessage($sDateName, RunWait(@ComSpec & " /c " & $sCommands, "", @SW_SHOW , $stdout_child), 4)

And here the Output from the file

powershell import-module UpdateServices; "Get-WsusUpdate -UpdateID *ID-was-correct* | Approve-WsusUpdate -Action Install -TargetGroupName TEST"
2015-04-17/08:46:57 - logged 1 Failure @error: 0

Don´t care about the failure - i will have to modify the _LogMessage, but i don´t know what an Exit code of a successful run looks like, yet or id i even can use this function.. My only question: Is this part of the script correct? I am not able to read the message from the powershell, it disappears too fast. Copying the first line directly in the powershell (without the word "powershell ") didn´t display an error.

Parameters of _Log_Message:

$sDateName is just the path and the filename (DateName because it contains date and time for the logfile)

RunWait(...): The function Needs the ExitCode

4: Just a Kind of function type, which influences whether it is success or failure (some functions return 0 when success, some 1, and some any value)

Edited by 25x14
Link to comment
Share on other sites

Now i tried myself a bit more, and i wrote a function for the updates. Now it is much easier to Show you the most important part of the script and everything which has to do with the powershell. Still no success.

In the "main program", i have some old lines as comments but not removed. Just to Show how i did it before (also didn´t work).

Func _InstallUpdate($ipCount, $spGroup, $spInstall)
    Switch $spInstall
        Case True
            ;approve Updates here using powershell
            $sCommands = 'powershell import-module UpdateServices; Get-WsusUpdate -UpdateID ' & IniRead($sUpdatIni, $aUpdateDatabase[$ipCount], "updateid", "default") & ' | Approve-WsusUpdate -Action Install -TargetGroupName ' & $spGroup
            _LogComment($sDateName, $sCommands)
            _LogMessage($sDateName, RunWait(@ComSpec & " /c " & $sCommands, "", @SW_SHOW , $stdout_child), 4)
        Case False
            ;Deny Updates Using Powershell for the group
            $sCommands = 'powershell import-module UpdateServices; Get-WsusUpdate -UpdateID ' & IniRead($sUpdatIni, $aUpdateDatabase[$ipCount], "updateid", "default") & ' | Approve-WsusUpdate -Action NotApproved -TargetGroupName ' & $spGroup
            _LogComment($sDateName, $sCommands)
            _LogMessage($sDateName, RunWait(@ComSpec & " /c " & $sCommands, "", @SW_SHOW , $stdout_child), 4)
        Case Else
            _LogComment($sDateName, "FATAL ERROR approving update " & IniRead($sUpdatIni, $aUpdateDatabase[$ipCount], 'updateid', "default") & "in function _InstallUpdate!")
            _LogComment($sDateName, "Please contact the author of the program!")
    EndSwitch
EndFunc   ;==>_InstallUpdate




;the main program
$sProgramName = _GetApplicationName_Ini()
$sGroupIni = IniRead($sProgramName, "Settings", "groupini", @ScriptDir) & '\Groups.ini'
$sUpdatIni = IniRead($sProgramName, "Settings", "updateini", @ScriptDir) & '\Updates.ini'

;copy the powershell-scripts that they can be run
_createFiles()

;this inifile is needed to create the dropdown-menue for the groups - OLD
$sCommands = '-ExecutionPolicy ByPass -noexit ' & @ScriptDir & '\GroupRead.ps1 -FilePath ' & $sGroupIni
;ShellExecuteWait("powershell.exe", $sCommands)

;create the inifile with all the updates - OLD
$sCommands = '-ExecutionPolicy ByPass -noexit ' & @ScriptDir & '\UpdateRead.ps1 -FilePath ' & $sUpdatIni
;ShellExecuteWait("powershell.exe", $sCommands)

;try 2, from AUTOIT-Forum
;$sCommands = 'powershell -Command import-module UpdateServices; "Invoke-Expression ' & @ScriptDir & '\GroupRead.ps1 -ExecutionPolicy ByPass -FilePath ' & $sGroupIni & '"'
$sCommands = 'powershell import-module UpdateServices; & "' & @ScriptDir & '\GroupRead.ps1 -ExecutionPolicy ByPass -FilePath ' & $sGroupIni & '"'
_LogComment($sDateName, $sCommands)
$iPID = RunWait(@ComSpec & " /c " & $sCommands, "", @SW_SHOW , $stdout_child)


;only run if all files for the program can be found, else: error because of the array
If Not FileExists($sProgramName) Then
    MsgBox(0, "Error", "The file " & $sProgramName & " was not found, the program can´t start")
ElseIf Not FileExists($sGroupIni) Then
    MsgBox(0, "Error", "The file " & $sGroupIni & " was not created, the program can´t start" & @CRLF & "You may check the entry in the " & $sProgramName & " or the script permissions")
ElseIf Not FileExists($sUpdatIni) Then
    MsgBox(0, "Error", "The file " & $sUpdatIni & " was not created, the program can´t start" & @CRLF & "You may check the entry in the " & $sProgramName & " or the script permissions")
Else
    ;create the dropdown-menue - save all the updates in the inifile in an array - open the gui (similar to the tc-config)
    _CreateChoice()
    _CreateUpdateArray()
    _createGui()
EndIf
;cleanup
_deleteFiles()
Link to comment
Share on other sites

Two Things:

 

Do you see UpdateServices available when you run this?

#include <AutoItConstants.au3>

$sCommands = 'powershell -Command "get-module -ListAvailable"'
$iPID = Run(@ComSpec & " /k " & $sCommands, "", @SW_SHOW , $stdout_child)

$sOutput = ""

 While 1
        $sOutput &= StdoutRead($iPID)
        If @error Then
            ExitLoop
        EndIf
    WEnd


msgbox(0, '' , $sOutput)

If so,  can you see the module load when you run this?

#include <AutoItConstants.au3>

$sCommands = 'powershell -Command "import-module UpdateServices"'
$iPID = Run(@ComSpec & " /k " & $sCommands, "", @SW_SHOW)

should look something like

post-59031-0-60110300-1429276185_thumb.p

 

Edited by boththose

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Link to comment
Share on other sites

Two Things:

 

Do you see UpdateServices available when you run this?

#include <AutoItConstants.au3>

$sCommands = 'powershell -Command "get-module -ListAvailable"'
$iPID = Run(@ComSpec & " /k " & $sCommands, "", @SW_SHOW , $stdout_child)

$sOutput = ""

 While 1
        $sOutput &= StdoutRead($iPID)
        If @error Then
            ExitLoop
        EndIf
    WEnd


msgbox(0, '' , $sOutput)

If so,  can you see the module load when you run this?

#include <AutoItConstants.au3>

$sCommands = 'powershell -Command "import-module UpdateServices"'
$iPID = Run(@ComSpec & " /k " & $sCommands, "", @SW_SHOW)

should look something like

Module_Loading.png

 

I see all the modules in the first script of yours including the UpdateServices, only in the second one, i just see a blank CMD-console (not powershell). But when i run it on a PC that doesn´t have the update-module, it displays an error. But i am really wondering about the blank screen. It doesn´t say anything about the import.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...