I am using powershell 1.0 and I need to install a service on a remote machine and first uninstall it if it exists.
This is my script I have that installs the service, however, I seem unable to uninstall the
service. I have tried installutil however the service path is a network path which installutil, throws errors over.
I'm sure there must be a better and cleaner way of approaching this.
$class = "Win32_Service"
$method = "Create"
$mc = [wmiclass]"\\DUMMYServer\ROOT\CIMV2:$class"
$inparams = $mc.PSBase.GetMethodParameters($method)
$inparams.DesktopInteract = $false
$inparams.DisplayName = "DummyService"
$inparams.ErrorControl = 0
$inparams.LoadOrderGroup = $null
$inparams.LoadOrderGroupDependencies = $null
$inparams.Name = "DummyMessageService"
$inparams.PathName = '\\DummyServer\c$\Applications\DummyMessageWindowsService\DummyWindowsService.exe'
$inparams.ServiceDependencies = $null
$inparams.ServiceType = 16
$inparams.StartMode = "Automatic"
$inparams.StartName = $null # will start as localsystem builtin if null
$inparams.StartPassword = $null
$result = $mc.PSBase.InvokeMethod($method,$inparams,$null)
$result | Format-List
If you're stuck on PowerShell 1.0, check out psexec which will allow you to run installutil.exe on the remote machine. If you were on PowerShell 2.0 on both the local and remote machines, you could use remoting to run installutil.exe on the remote machine.
Related
I wrote some code on my Windows 7 administration machine, where it just worked fine. Now I want to run it from a console - commandline with administration access from a client machine on Windows 10.
The script throws the error when it tries to Register the task through the COM-Object of the Task-Scheduler:
Value does not fall within the expected range:
# Aufruf in der command line mit
# powershell.exe -file C:\Workspace\controlling-macros\TaskCreator.ps1
$path = "C:\Workspace\controlling-macros\FullWorkbookPathsMR.csv"
$csv = Import-CSV -Path $path -Delimiter ";" | % {
# The name of the scheduled task
[string]$TaskName = "$($_.reportsource) - $($_.reportname) - $($_.reportid)"
# The description of the task
[string]$TaskDescr = "Hello, it's you again! I am $($_.reportname) and I will get started, when Report ID $($_.reportid) is fired. Have a nice day!"
# The Task Action command
$TaskCommand0 = "cmd"
$TaskCommand1 = "`"C:\Program Files (x86)\Microsoft Office\Office14\EXCEL.EXE`""
# The Task Action command argument
$TaskArg = "/c C:\Windows\System32\taskkill.exe /F /IM EXCEL.EXE"
$TaskArg1 = "$($_.fullpath)"
# attach the Task Scheduler com object
$service = new-object -ComObject("Schedule.Service")
# connect to the local machine.
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa381833(v=vs.85).aspx
$service.Connect()
$rootFolder = $service.GetFolder("\")
$TaskDefinition = $service.NewTask(0)
$TaskDefinition.RegistrationInfo.Description = "$TaskDescr"
$TaskDefinition.Settings.Enabled = $true
$TaskDefinition.Settings.AllowDemandStart = $true
$triggers = $TaskDefinition.Triggers
#http://msdn.microsoft.com/en-us/library/windows/desktop/aa383915(v=vs.85).aspx
$trigger = $triggers.Create(0) # Creates an "On an event" trigger
$trigger.Subscription = "<QueryList><Query Id='0'><Select Path='Application'>*[System[Provider[#Name='$($_.reportsource)'] and EventID='$($_.reportid)']]</Select></Query></QueryList>"
# "*[System[Provider[#Name='$reporttype'] and EventID=$reportid]]"
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa381841(v=vs.85).aspx
$Action = $TaskDefinition.Actions.Create(0)
$action.Path = "$TaskCommand0"
$action.Arguments = "$TaskArg"
$Action = $TaskDefinition.Actions.Create(0)
$action.Path = "$TaskCommand1"
$action.Arguments = "$TaskArg1"
#http://msdn.microsoft.com/en-us/library/windows/desktop/aa381365(v=vs.85).aspx
$rootFolder.RegisterTaskDefinition("$TaskName", $TaskDefinition, 6, "System", $null, 5) # <<--- here the error occurs
Write-Host $($_.sequence) $($_.reportsource) $($_.reportname) $($_.reportid) $($_.fullpath) "task created successfully."
}
why no data is piped to the variables?
I know this seems basic but I would start by matching Powershell versions first as different versions of Powershell do compile some code differently as well as some cmdlets just do not work in older versions.
In new-scheduledtasksettingsset there is a compatibility switch (v1, vista, win7, win8).
As I'm new to PowerShell and also DSC (and programming in total) i have a question to which i couldn't find an answer in the web.
I'm trying to install an msi (or an exe) with PS DSC. I sucessfully wrote a script to check and install windows-features and to install JDK and set the ressources.
But with my next step I seem to be overchallenged.
so heres my code so far:
$ConfigurationData = #{
AllNodes = #(
#{
NodeName="*"
PSDscAllowPlainTextPassword=$true
}
)
}
Configuration AppFabric
{
param (
$TargetNodes,
[Parameter(Mandatory=$false)]
[PSCredential]$Credential
)
Import-DscResource –ModuleName ’PSDesiredStateConfiguration’
Node localhost
{
Package AppFabric
{
Ensure = "Present"
Name = "AppFabric"
Path = "$PWD\src\AppFabric\package\appfabric-1.1-for-windows-server-64.msi"
ProductId = ""
LogPath = "$PWD\logs\$env:computername-AppFabric"
Arguments = "/i HostingServices,CacheClient,HostingServicesAdmin"
Credential = "$Credential"
}
}
}
AppFabric -OutputPath $PWD\mof\AppFabric\
Start-DscConfiguration -Path $PWD\mof\AppFabric\ -wait -verbose -Force
So as you see i'm trying to install AppFabric on a Windows Server 2012R2 up to date.
When i Run the script i get following error:
I have no clue, what that means and can't find anything on the web that could help.
If you need further information, let me know, as I said, I'm new to this :x
Thanks!
Edit:
If I try to do it without credentials I get the following:
VERBOSE: Perform operation 'Invoke CimMethod' with following parameters, ''methodName' = SendConfigurationApply,'className' = MSFT_DSCLocalConfigurationManager,'namespaceName' = root/Microsoft/Windows/DesiredStateConfiguration'.
You are treating the Credential property as a string instead of PSCredential.
Remove double quotes from Credential property to fix the issue.
Package AppFabric
{
Ensure = "Present"
Name = "AppFabric"
Path = "$PWD\src\AppFabric\package\appfabric-1.1-for-windows-server-64.msi"
ProductId = ""
LogPath = "$PWD\logs\$env:computername-AppFabric"
Arguments = "/i HostingServices,CacheClient,HostingServicesAdmin"
Credential = $Credential
}
When attempting to access a network shared folder, DSC returns an "Access is denied" error, despite that I have provided a valid credential to it.
I'm using a DSC configuration, where a DSC "Script" resource is as follows:
Script myScriptResource {
GetScript = {return $true}
SetScript = {
$setupShare = '\\SomeNetworkSharesFolder\subFolder'
# This line produces valid results when run directly on node VM.
$build = Get-ChildItem "FileSystem::$setupShare" -Name | Sort-Object -Descending | Select-Object -First 1 | Out-String
Write-Host "Final Build: $build"
}
TestScript = {return $false} #Always run Set-Script block!
Credential = $ValidNetworkShareCredential
PsDscRunAsCredential = $ValidNetworkShareCredential
}
I receive an error:
VERBOSE: [MyNodeVM]: [[Script]myScriptResource] Performing the operation "Set-TargetResource" on target "Executing t
he SetScript with the user supplied credential".
Access is denied
+ CategoryInfo : PermissionDenied: (\\SomeNetworkSharesFolder\subFolder:) [], CimException
+ FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
+ PSComputerName : myNodeVM
This might be due to the fact the LCM on the node VM is using a local SYSTEM user credential by default.
I attempted to change the user credential manually by navigating to the windows services manager (Hint: RUN then services.msc), and change the user credential in the logon tab of winRM service properties. Everytime I attempt to run the Windows Remote Management (WS-Managment) service, I receive and error:
Windows could not start the Windows Remote Management (WS-Management) service on Local Computer.
Error 1079: The account specified for this service is different from the account specified for other services running in the same process.
I don't know how to change the credential of LCM so that it can access the network shared folder upon the execution of Get-ChildItem.
Script myScriptResource {
GetScript = {return $true}
SetScript = {
$username ="someusername"
$secpasswd = ConvertTo-SecureString “somepassword” -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ($username, $secpasswd)
$setupShare = '\\SomeNetworkSharesFolder\subFolder'
$psDriveArgs = #{ Name = ([guid]::NewGuid()); PSProvider = "FileSystem"; Root = $setupShare; Scope = "Private"; Credential = $mycreds }
new-psdrive #psDriveArgs -ErrorAction Stop
# This line produces valid results when run directly on node VM.
$build = Get-ChildItem "FileSystem::$setupShare" | Sort-Object -Descending | Select-Object -First 1 | Out-String
Write-Host "Final Build: $build"
}
TestScript = {return $false} #Always run Set-Script block!
}
There isn't an easy way to make it work with script resource because you need an ability to pass credentials to the script resource so that you can mount a drive and use it to copy/paste. If you want to copy files/directory from the share you can use 'File' resource. If you want to copy files/directory to the share you can use 'xFileUpload' resource from xPsDesiredStateConfiguration (https://gallery.technet.microsoft.com/xPSDesiredStateConfiguratio-417dc71d) Module. If you really need to use script resource to do this job, look into how xFileUpload resource is doing it.
$filter = ([wmiclass]"\\.\root\subscription:__EventFilter").CreateInstance()
$filter.QueryLanguage = "WQL"
$filter.Query = "Select * from __InstanceCreationEvent within 5 where targetinstance isa 'win32_logicaldisk'"
$filter.Name = "USBFilter"
$filter.EventNamespace = 'root\cimv2'
$result = $filter.Put()
$filterPath = $result.Path
$consumer = ([wmiclass]"\\.\root\subscription:CommandLineEventConsumer").CreateInstance()
$consumer.Name = 'USBConsumer'
$consumer.CommandLineTemplate = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe –ExecutionPolicy Bypass -file C:\test.ps1"
$consumer.ExecutablePath = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$consumer.WorkingDirectory = "C:\"
$result = $consumer.Put()
$consumerPath = $result.Path
$bind = ([wmiclass]"\\.\root\subscription:__FilterToConsumerBinding").CreateInstance()
$bind.Filter = $filterPath
$bind.Consumer = $consumerPath
$result = $bind.Put()
$bindPath = $result.Path
The above code is supposed to run a script when windows detects a USB device is inserted it runs fine (no error/warnings/exceptions) however on the insertion of a device, the script, which is supposed to display a message box. Doesn't. I have tested the triggered script on its own and the dialogue box displays fine.
I am really not all that familiar with WMIs and persistant one even less, so any help at all would be greatly appreciated
Since the event consumer will be invoked by a WMI host process running under the SYSTEM account, you won't see anything in your own desktop session.
If you change your C:\test.ps1 contents to write to the event log instead:
$LogSource = "USB Detector"
if(-not [System.Diagnostics.EventLog]::SourceExists($LogSource))
{
New-EventLog -LogName Application -Source $LogSource
}
Write-EventLog -LogName Application -Source $LogSource -EventId 100 -Message "New disk attached!"
You'll see that it works fine:
I have used Power Shell to check if a path exists using this command . powershell test-path "HKCU:\Software\Microsoft\Windows" now how can the same be extended to remote machine. What is the syntax if i want to test a registry path in Remote machine, i tried powershell test-path "\\machinename\HKCU:\Software\Microsoft\Windows" and its not working. Suggest some way to test it.
You can access it as outlined here: http://powershell.com/cs/blogs/tips/archive/2011/02/15/accessing-registry-remote.aspx
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', 'server123')
$key = $reg.OpenSubKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall')
$key.GetSubKeyNames() | ForEach-Object {
$subkey = $key.OpenSubKey($_)
$i = #{}
$i.Name = $subkey.GetValue('DisplayName')
$i.Version = $subkey.GetValue('DisplayVersion')
New-Object PSObject -Property $i
$subkey.Close()
}
$key.Close()
$reg.Close()
An alternative is to enable PSRemoting and use invoke-command on the remote machine and effectively run the same command as what you would run on the local box.
You cannot connect to the current user hive of a remote computer. Here's an example of using the Remote Regitry module to check if a remote key exists in the hklm hive of a remote server. The module can be found on codeplex: psremoteregistry.codeplex.con
Test-RegKey -ComputerName server1 -Key software\microsoft\winows -Hive LocalNachine
This site helped me. The code basically checks for one key and then checks for another one if the first one does not exist. It also verifies that the subkey exists before trying to read a value from it. If neither exist a try / catch can help deal with that.
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $computerName)
$regkey = $reg.OpenSubkey("SOFTWARE\\Symantec\\Symantec Endpoint Protection\\AV\\Storages\\Filesystem\\RealTimeScan")
if(-not $regkey) {
$regkey = $reg.OpenSubkey("SOFTWARE\\Wow6432Node\\Symantec\\Symantec Endpoint Protection\\AV\\Storages\\Filesystem\\RealTimeScan")
}
$autoProtectStatus = ""
$null = ""
if ($regkey.GetValue("OnOff", $null) -ne $null) {
$autoProtectStatus = $regkey.GetValue("OnOff")
}
if ($autoProtectStatus -eq 1) {
$autoProtectStatus = "Protection On"
} elseif ($autoProtectStatus -eq 0) {
$autoProtectStatus = "Protection Off"
} else {
$autoProtectStatus = "Unknown State"
}
So much of the Q&A is 3 years old or older. I suspect the newer versions of Powershell must have cleaned up a lot of this. Having said that, there is still not a direct command to check the registry on a remote computer (to the best of my knowledge). This works - it checks if .NET 4.6.2 is installed (is it simpler than the other answers though?)
invoke-command -computername <NetBiosName> -scriptblock {test-path -Path
"HKLM:\Software\Microsoft\.NetFramework\v4.0.30319\SKUs\.NetFramework,
Version=v4.6.2"}
You can also put the scriptblock content into a *.ps1 file (everything inside the {} and then invoke it with: Invoke-Command -ComputerName NetBiosName -FilePath "FQLP"