I have made a script for adding a printer and port to a print server. The server handles the queue's and uses add a queue to start printing. However since the server is quite far from many of the printers i would like to activate the option "Print directly to the printer" (Which is found in, Printer ->Properties -> Advanced)
What is the PowerShell equivalent for this option?
$PortName = Read-Host "Name of port : "
$PortIp = Read-Host "IP Adress : "
Add-PrinterPort -Name $PortName -PrinterHostAddress $PortIp
Get-PrinterDriver
Write-Host "---------------------"
$PrintDriver = Read-Host "Print driver :"
if ($PrintDriver.Equals("HP")){ $PrintDriver = "HP Universal Printing PCL 6"}
$PrinterLocation = Read-Host "Location : "
Add-Printer -Name $PortName -DriverName $PrintDriver -Shared -Location $PrinterLocation -Published -PortName $PortName
I have tried -RenderingMode but i couldnt see that that made any difference
You can do this with PowerShell and WMI:
$printer = Get-WmiObject -Class Win32_Printer -Filter "Name = 'PrinterName'"
$printer.Direct = $true
$printer.Put()
Probably should put a try {} catch {} around that as well.
This will also set the SpoolerEnabled (deprecated read only property) and the DoCompleteFirst property both to $false.
http://www.powertheshell.com/reference/wmireference/root/cimv2/win32_printer/
Related
So far I have this:
$port = Get-PrinterPort -Name USB001
if ($port -eq $null) {
Add-PrinterPort -Name USB001 -PrinterHostAddress "\\localhost" -PrinterPortType USB - ErrorAction SilentlyContinue
}
$printerParams = #{
Name = "HP LaserJet MFP M232sdw"
DriverName = "HP LaserJet MFP M232-M237 PCLm-S"
Port = $port.Name
Verbose = $true
}
I dont know where to begin to move past looking at USB001. In the end I want this script to find the first unusued USB port and assign that to the printer.
`
-Thank you
I feel like I need to add an else clause but im not sure where to begin. This is part of a major project for me at a new job so any help would be appreciated.
I am currently working in Powershell. I have created a Script that allows me to install the specified printer to any given machine on our network. However, I need help with adding Parameters(Variables) so that I do not have to go back into the code each time and manually change the Printer and Its Driver/IP.
<# Declare name of the Port #>
$portName = "TCPPort:xx.xx.xx.xx"
<# Declares the name of the Printers Driver #>
$printDriverName = "HP LaserJet Pro M402-M403 PCL 6"
<# If the printer exists, get the port for it, and assign the name of it to -Name $portname #>
$portExists = Get-Printerport -Name $portname -ErrorAction SilentlyContinue
<# If the Port does not exist, Add the provided port name, assign it as the Printerhostaddress #>
if (-not $portExists) {
Add-PrinterPort -name $portName -PrinterHostAddress ""
}
$printDriverExists = Get-PrinterDriver -name $printDriverName -ErrorAction SilentlyContinue
<# Once the PrintDriver is obtained, Add the Printer, assign the name,portname, and driver name. Install to designated system #>
if ($printDriverExists){
Add-Printer -Name "CRCHRDirHP2" -PortName $portName -DriverName $printDriverName
}else{
Write-Warning "Printer Driver not installed"
}
This is an example of how your code would look if it was a function, I've changed the if statements for try / catch statements. The function is using [cmdletbinding()], this will allow you to use CommonParameters, in example, -Verbose if you want to display the Write-Verbose comments.
function Install-Printer {
[cmdletbinding()]
param(
[Parameter(Mandatory)]
[string]$PrinterName,
[Parameter(Mandatory)]
[string]$PortName,
[Parameter(Mandatory)]
[string]$DriverName
)
try
{
Write-Verbose 'Attempting to get Printer Port'
# If this fails, it will go to `catch` block
$null = Get-Printerport -Name $PortName
}
catch
{
Write-Verbose 'Port does not exist. Adding new Printer Port.'
Add-PrinterPort -Name $PortName -PrinterHostAddress ""
}
try
{
Write-Verbose 'Adding printer...'
$null = Get-PrinterDriver -Name $DriverName
Add-Printer -Name $PrinterName -PortName $PortName -DriverName $DriverName
Write-Verbose 'Printer added successfully.'
}
catch
{
Write-Verbose 'Failed to add printer, error was:'
$PSCmdlet.WriteError($_)
}
}
Usage:
Install-Printer -PrinterName "CRCHRDirHP2" -PortName "TCPPo...." -DriverName "HP LaserJet..."
In addition to Santiago's answer, if you have some source for the variables it would make things a lot easier. For instance consider the following CSV file 'printers.csv' in C:\Temp:
name,portName,driverName
CRCHRDirHP2,TCPPort123,HP LaserJet
CRCHRDirHP3,TCPPort1234,HP LaserJet
CRCHRDirHP4,TCPPort12345,HP LaserJet
Now we import the file and start looping through the printers to call the function that Santiago made and use the variables from the input file.
$printers = Import-CSV C:\Temp\printers.csv
foreach($printer in $printers){
Write-Verbose "Processing printer $($printer.name)"
try{
Install-Printer -PrinterName $printer.name -PortName $printer.portName -DriverName $printer.driverName
}catch{
Write-Verbose "Printer $($printer.name) failed with error: $_"
}
}
I'm writing a script on HYPER-V host for getting VMs guest informations. Is there a way to get VMs Operating System name from Hyper-V using powershell?
There are several examples using (Get-WmiObject Win32_OperatingSystem -ComputerName $vmName).name but i should get this information directly from Hyper-V because of domain restrictions.
Also i'm using hyper-v module of powershell but i couldn't see any cmdlets related to OS.
This could be retrieved from guest intrinsic exchange items.
# Filter for parsing XML data
filter Import-CimXml
{
# Create new XML object from input
$CimXml = [Xml]$_
$CimObj = New-Object -TypeName System.Object
# Iterate over the data and pull out just the value name and data for each entry
foreach ($CimProperty in $CimXml.SelectNodes("/INSTANCE/PROPERTY[#NAME='Name']"))
{
$CimObj | Add-Member -MemberType NoteProperty -Name $CimProperty.NAME -Value $CimProperty.VALUE
}
foreach ($CimProperty in $CimXml.SelectNodes("/INSTANCE/PROPERTY[#NAME='Data']"))
{
$CimObj | Add-Member -MemberType NoteProperty -Name $CimProperty.NAME -Value $CimProperty.VALUE
}
# Display output
$CimObj
}
# Prompt for the Hyper-V Server to use
$HyperVServer = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)"
# Prompt for the virtual machine to use
$VMName = Read-Host "Specify the name of the virtual machine"
# Get the virtual machine object
$query = "Select * From Msvm_ComputerSystem Where ElementName='" + $VMName + "'"
$Vm = gwmi -namespace root\virtualization\v2 -query $query -computername $HyperVServer
# Get the KVP Object
$query = "Associators of {$Vm} Where AssocClass=Msvm_SystemDevice ResultClass=Msvm_KvpExchangeComponent"
$Kvp = gwmi -namespace root\virtualization\v2 -query $query -computername $HyperVServer
Write-Host
Write-Host "Guest KVP information for" $VMName
# Filter the results
try {
$Kvp.GuestIntrinsicExchangeItems | Import-CimXml | where Name -eq "OSName"
}
catch {
Write-Host "Not found"
}
From Ben Armstrong’s Virtualization Blog.
Unless you're using SCVMM, Guest OS details are not available via Hyper-V PowerShell cmdlets.
You have to query the Guest itself like you've already found.
I couldn't run t1meless' script on PowerShell version 7.1, because gwmi is deprecated in 7.1, sources MS Docs and GitHub.
I rewrote the script for PS 7.1.
# Script for retrieving Hyper-V Guest Operating System.
# Tested on PowerShell 7.1
# Prompt for the Hyper-V Server to use
$hyper_v_server = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)"
# Prompt for the virtual machine to use
$vm_name = Read-Host "Specify the name of the virtual machine"
# Check if VM exists and is running. This script doesn't work if the VM is stopped.
# Capture error output, source: https://stackoverflow.com/a/66861283/3498768
$vm_not_found = $($vm_state = (Get-VM $vm_name).state) 2>&1
if ($vm_not_found -ne $null) {
Write-Host "$vm_name VM was not found."
exit
}
if ($vm_state -eq "Off") {
Write-Host "Cannot retrieve information of $vm_name. The VM is stopped. Only running VM information can be retrieved."
exit
}
# Get the virtual machine object
$query = "Select * From Msvm_ComputerSystem Where ElementName='" + $vm_name + "'"
$vm = Get-CimInstance -namespace root\virtualization\v2 -query $query -computername $hyper_v_server
# Get associated information
$vm_info = Get-CimAssociatedInstance -InputObject $vm
Write-Host "Guest information for" $vm_name
# Select only required information
$vm_info | Where GuestOperatingSystem |
Select -Property GuestOperatingSystem |
Format-List *
I currently have a VBScript that reads a list of servers, and attempts to verify the password of a specific userid. The userid is locally on that server. I am checking to see that the password is not set to the default (I want to make sure it was changed to something else).
The "list of servers" can be a mix of IP addresses, hostnames (like Rocky), or fully qualified DNS names (like rocky.bigcompany.com). The servers are a mixture of physical and virtual devices, and may or may not be on a domain.
The existing VBScript I wrote handles all this, and works fine. I'm trying to re-write this same program in Powershell, and It's not working.
Here's the function I have in VBScript that does what I want:
Function LoginToServer(Computer, username, password)
'this function will log into a server
On Error Resume next
Set locator = CreateObject("WbemScripting.SWbemLocator")
Set wmi = locator.ConnectServer(computer, "root\cimv2", username, password)
'check the error code and see if we logged in successfully
LoginRC = Err.Number
If LoginRC <> 0 Then
msg = "Could not log into server: " & CStr(computer) & " With ID: " & CStr(username)
lfo.lmsg "B", "WARN", msg
Else
msg = "Server: " & CStr(computer) & " Logged in successfully as: " & CStr(username)
lfo.lmsg "B", "INFO", msg
End If
wmi.Security_.ImpersonationLevel = 3
'return the code back to calleer
LoginToServer = LoginRC
End Function
… and here's what I've tried to do in PowerShell:
Param($ComputerName = "LocalHost")
$ErrorActionPreference = "Stop"
# Actual Code starts here
Write-Host "Attempting to ping server: $ComputerName"
$IPResult = Test-Connection -ComputerName $ComputerName -Quiet
if ($IPResult -eq "TRUE") {
Write-Host "Ping OK - now attempting to log in"
try {
$ID = "userid"
$PSW = "password"
$password = ConvertTo-SecureString $PSW -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ($ID, $password)
$sesh = New-PSSession -ComputerName $ComputerName -Credential $cred
} catch {
Write-Host "Error caught"
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
} finally {
$Time = Get-Date
"$Time Computer: $ComputerName ERROR: $ErrorMessage ITEM: $FailedItem" |
Out-File c:\temp\TestCredScript.log -Append
}
} else {
Write-Host "Could not ping server"
}
How do I log into these remote computers with an ID and Password using PowerShell?
Your two code samples do different things. The VBScript code connects via WMI whereas the PowerShell code tries to establish a PowerShell session. For the latter you need PowerShell Remoting enabled, which you probably don't have.
While you probably may want to enable PSRemoting anyway, you can also use WMI from PowerShell. The Get-WmiObject cmdlet allows you to provide credentials and impersonation level, so you don't need to establish a connection first like you need to do with VBScript (if you want to use explicit credentials).
Example querying the Win32_Process class on a remote computer:
$computer = '...'
$username = 'userid'
$password = 'password'
$pw = ConvertTo-SecureString $password -AsPlainText -Force
$cred = New-Object Management.Automation.PSCredential ($username, $pw)
Get-WmiObject -Computer $computer -Namespace 'root\cimv2' -Class Win32_Process -Impersonation 3 -Credential $cred
See here for further information.
WMI can do it, but I have an issue, PCs are on, but logged off. If I try to run:
wmic /node:%strIP% printer where DeviceID="lp1" set DriverName="Lexmark Universal v2"
It fails with a message about a "generic failure". I RDP in and then run the same command from my end, and it works. Powershell version I am using is older, so it does not have some of the printer cmdlets, and updating PS is currently out of the question. Is there a way to remotely log someone in, without actually having to RDP in? Via PS, cmd, PSEXEC, etc?
The other avenue I've taken is using regedit, but I'm hitting some hicups with that, namely that I cannot figure out what to copy. In regedit, I can change the drivername and the setting that enable duplex and tray2 (in printer settings), but I cannot figure how to change the settings in printer preferences for printing double sided and doing so along the long edge.
What I did to figure out what to change, I did a find on the printer name in regedit as a data value and exported the keys before changing the settings. Then I exported it again AFTER changing the settings. I then used fc /c /a /u before.reg after.reg to get the changes. I chopped up the .reg to include only the changed values. Running the .reg seems to change everything, but the print both sides, along the long edge settings. It is a lexmark printer, so I am wondering if maybe preferences for it are stored elsewhere.
This is my most up to date PS1 script. I've commented out some lines as I tried different ways of doing things:
$Cred = Get-Credential
$Str = Read-Host "Please select a site ID [###] "
$PC = Read-Host "Please select a PC number [##] "
Clear-Host
$PCNm = "$Str-CCPC-$PC"
function Test-PsRemoting
{
try
{
$errorActionPreference = "Stop"
$result = Invoke-Command -ComputerName $PCNm { 1 }
}
catch
{
Write-Verbose $_
return $false
}
if($result -ne 1)
{
Write-Verbose "Remoting to $PCNm returned an unexpected result."
return $false
}
$true
}
If(!(Test-PsRemoting)){
PSEXEC \\$PCNm powershell Enable-PSRemoting -force 2>&1 >nul
Clear-Host
Write-Host "Enabled PsRemoting"
}else{Write-Host "PsRemoting already enabled"}
Invoke-Command -ComputerName $PCNm -Credential $Cred -ScriptBlock {
#$lp1 = Get-WMIObject -Query "SELECT * from Win32_Printer Where DeviceID='lp1'"
$lp1 = Get-WmiObject Win32_Printer | ?{$_.name -eq "lp1"}
$lp1.Scope.Options.EnablePrivileges = $true
$lp1.DriverName = "Lexmark Universal v2"
$lp1R = $lp1.Put()
#$lp2 = Get-WMIObject -Query "SELECT * from Win32_Printer Where DeviceID='lp2'"
$lp2 = Get-WmiObject Win32_Printer | ?{$_.name -eq "lp2"}
$lp2.Scope.Options.EnablePrivileges = $true
$lp2.DriverName = "Lexmark Universal v2"
$lp2R = $lp2.Put()
}
#$lp1 = Get-WMIObject -Impersonation Delegate -Authentication Call -Credential $Cred -ComputerName $PCNm -Query "SELECT * from Win32_Printer Where DeviceID='lp1'"
#$lp1.DriverName = "Lexmark Universal v2"
#$lp1.Put()
No matter which way I try it, invoke-command, or get-wmiobject, I get:
Exception calling "Put" with "0" argument(s): "Generic failure "
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
+ PSComputerName : 150-CCPC-02
This doesn't particularly answer your actual question but as a solution for how I do this very same thing I thought I would give you what I threw together to update printer properties. I have not cleaned this up at all as I was porting it from my create printer function.
Function Set-SSPrinter {
Param(
[Parameter(Mandatory=$true,
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$True)]
[ValidateNotNullOrEmpty()]
[string]$ComputerName,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$Name,
[string]$PortName,
[string]$DriverName,
[string]$Comment,
[string]$Location,
[bool]$Shared,
[string]$ShareName = $Name,
[string]$PermissionSDDL,
[string]$PrintProcessor,
[string]$DataType,
[bool]$RawOnly
)
try {
$modprinter = Get-WmiObject Win32_Printer -ComputerName $ComputerName | ?{$_.name -eq $Name}
$modprinter.Scope.Options.EnablePrivileges = $true
if($DriverName) {
$modprinter.DriverName = $DriverName
}
if($PortName) {
$modprinter.PortName = $PortName
}
if($Shared) {
$modprinter.Shared = $Shared
}
if($ShareName) {
$modprinter.ShareName = $ShareName
}
if($Location) {
$modprinter.Location = $Location
}
if($Comment) {
$modprinter.Comment = $Comment
}
if($Name) {
$modprinter.DeviceID = $Name
}
if($PrintProcessor) {
$modprinter.PrintProcessor = $PrintProcessor
}
if($DataType) {
$modprinter.PrintJobDataType = $DataType
}
if($RawOnly) {
$modprinter.RawOnly = $RawOnly
}
$result = $modprinter.Put()
if($PermissionSDDL) {
$modprinter.SetSecurityDescriptor($objHelper.SDDLToWin32SD($PermissionSDDL).Descriptor) | Out-Null
}
$("Update Complete: " + $Name)
} catch {
$("Update Failed: " + $Name)
Write-Warning $_.Exception.Message
$error.Clear()
}
}
Unfortunately I use the printer name to figure out which device to modify on the remote machine. Your executing credentials from the powershell session you have open must have admin rights on the remote machine. if necessary do a runas different user on powershell.exe
Example usage:
Set-SSPrinter -ComputerName "10.210.20.100" -Name "TestPrinter" -DriverName "Lexmark Universal v2"
wmic /node:servername /user:username /password:password path win32_something call methodname
Is how to do it.
Things with users are best done with logon scripts because that is how windows is designed.