Powershell how to pipe an interactive command - windows

I am connection to a database via an interactive SQL-Command-Line-Utility and when I am executing an SQL command, I want to pipe the output to another power shell cmdlet, for example out-gridview.
Lets say for example I connect to a Sybase ASE database, and I login with
C:\users\user>isql -U<user> -S<SI>
[password]:
1>use master
2>go
1>SELECT * FROM sysusers
2>go | out-gridview
The pipe to out-gridview, nor any other cmdlet, is working. I can redirect the output to a file via > nonetheless, but I think its pre-implemented in the isql-command-line-utility.
Has anyone an idea how to pipe this stuff? I am well aware that there are scripts like this
$query="select * from syslogins"
$conn=New-Object System.Data.Odbc.OdbcConnection
$conn.ConnectionString= "driver={Adaptive Server Enterprise};
dsn=SERVER_NAME;db=master;na=IP,PORT;uid=SOMEUSER;pwd=******;"
$conn.open()
$cmd=new-object System.Data.Odbc.OdbcCommand($query,$conn)
$cmd.CommandTimeout=30
write-host $query
$ds=New-Object system.Data.DataSet
$da=New-Object system.Data.odbc.odbcDataAdapter($cmd)
write-host $ds
$da.fill($ds)
$ds.Tables[0] | out-gridview
$conn.close()
But I dont' want to store my password in clear text inside of a script. I want to login to a session, then execute the commands and then pipe my information.

You can't use cmdlets inside a console application. Console applications return text, while cmdlets work with object. You would need to use something like your second sample or run a "script" in isql and parse the text-output to objects.
Since you don't want to automate this you could simply use Read-Host to get the password when running the script.
#Ask for password
$pass = Read-Host Password
$query="select * from syslogins"
$conn=New-Object System.Data.Odbc.OdbcConnection
#User password-variable in string
$conn.ConnectionString= "driver={Adaptive Server Enterprise};
dsn=SERVER_NAME;db=master;na=IP,PORT;uid=SOMEUSER;pwd=$pass;"
$pass = ""
$conn.open()
$cmd=new-object System.Data.Odbc.OdbcCommand($query,$conn)
$cmd.CommandTimeout=30
write-host $query
$ds=New-Object system.Data.DataSet
$da=New-Object system.Data.odbc.odbcDataAdapter($cmd)
write-host $ds
$da.fill($ds)
$ds.Tables[0] | out-gridview
$conn.close()

U can replace
go | out-gridview
with
go > out-gridview
In this way, U just redirected the output to out_gridview.

Related

Trying to write a powershell script that shows all locked files with computer names instead of IP address

The task given was to create a way for our staff to see who has the file open that they want to use, as Windows says it is either locked and doesn't name the person who has it locked, or it displays the person who made the file but not the person who currently has it open.
I can look it up in Computer Management on the fileserver, but were are hoping to speed up this for the end users.
I've written this powershell script on our fileserver and it works perfectly, I have this running every 5 minutes in Task Scheduler with administrative permissions:
get-smbopenfile -ClientUserName * |select clientcomputername,clientusername,path | Out-File -Encoding utf8 "S:\LockedFiles.txt" -width 300
The output looks like this:
clientcomputername clientusername path
------------------ -------------- ----
IPADDRESS DOMAIN\USERNAME S:\FOLDER\FILE.FILEEXTENSION
What I really want to do now is get the computer name rather than the IP address, just in case staff are logged into multiple machines at the same time.
I wondered if ClusterNodeName or PSComputerName would provide this, but the returned data is always blank.
I thought about this and below is one option (the first line is pseudocode), but as I see it that would mean recursively altering the piped data or reading in piped data, which I'm not even sure how to do.
$ipaddress = IPADDRESS
$Workstation = [System.Net.Dns]::GetHostByName($ipaddress)
Write-Host $Workstation.HostName
Anyone have any ideas on how I can do this? Is there a better way?
I assume you're looking to add a new property to your output object that has the resolved DNS Name from the IP Address found in the ClientComputerName property. For this you use Resolve-DnsName to attempt the name resolution and a Try Catch in case it fails to capture the exception message. For the export I would recommend you to use Export-Csv.
Get-SmbOpenFile -ClientUserName * | ForEach-Object {
$dnsName = try {
(Resolve-DnsName $_.ClientComputerName -ErrorAction Stop).NameHost
}
catch {
[ComponentModel.Win32Exception]::new($_.Exception.NativeErrorCode).Message
}
[pscustomobject]#{
ClientIpAddress = $_.ClientComputerName
ResolvedHostName = $dnsName
ClientUserName = $_.ClientUserName
Path = $_.Path
}
} | Export-Csv "S:\LockedFiles.csv" -Encoding utf8 -NoTypeInformation

Powershell script: List files with specific change date (Amount if possible)

For license porpuses I try to automate the counting process instead of having to login into every single server, go into directory, search a file name and count the results based on the change date.
Want I'm aiming for:
Running a powershell script every month that checks the directory "C:\Users" for the file "Outlook.pst" recursively. And then filters the result by change date (one month or newer). Then packing this into an email to send to my inbox.
I'm not sure if that's possible, cause I am fairly new to powershell. Would appreciate your help!
It is possible.
I dont know how to start a ps session on a remote computer, but I think the cmdlet Enter-PSSession will do the trick. Or at least it was the first result while searching for "open remote powershell session". If that does not work use the Invoke-Command as suggested by lit to get $outlookFiles as suggested below.
For the rest use this.
$outlookFiles = Get-ChildItem -Path "C:\Users" -Recurse | Where-Object { $_.Name -eq "Outlook.pst" }
Now you have all files that have this name. If you are not familiar with the pipe in powershell it redirects all objects it found with the Get-ChildItem to the next pipe section and here the Where-Object will filter the received objects. If the current object ($_) will pass the condition it is returned by the whole command.
Now you can filter these objects again to only include the latest ones with.
$latestDate = (Get-Date).AddMonths(-1)
$newFiles = $outlookFiles | Where-Object { $_.LastAccessTime -gt $latestDate }
Now you have all the data you want in one object. Now you only have to format this how you like it e.g. you could use $mailBody = $newFiles | Out-String and then use Send-MailMessage -To x#y.z -From r#g.b -Body $mailBodyto send the mail.

Unable to Output Data to text file

I am using the following script to pull a list of all my computers from my wsus server. It then places then in a neat list and this works fine.
However, when I try to output the data to a text file it creates the text file but writes no data. Is there something I am missing in the Output part? Full script below.
$wsus = 'halvedge2'
[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | Out-Null
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer()
$wsus.GetComputerTargets() | Select FullDomainName, LastReportedStatusTime, LastSyncTime
out-file -filepath "\\halvedge2\c$\PS1\WSUS\Last installed Update\updates.txt"
Additionally I would like to add an If statement to it looks at the LastSyncTime and for any LastSyncTime over 30 days it only returns them Computer Targets. How can I achieve this?
You do not have to out-file separately:
If the below yields value, then Instead of this:
$wsus.GetComputerTargets() | Select FullDomainName, LastReportedStatusTime, LastSyncTime
Do This:
$wsus.GetComputerTargets() | Select FullDomainName, LastReportedStatusTime, LastSyncTime | Out-File "D:\updates.txt" -Append -Force
Note: First try saving locally. If it works, then try remotely on the UNC. If remote fails, then give permission to the specific user to save it.

Deleting Report Server (2014 Native Mode) Encrypted Keys & Data [PowerShell]

After I clone an instance from an image, a few manual steps need to be carried out to get the report server working correctly. Among them is the deletion of all encrypted data, including symmetric key instances on the report server database.
This step requires me to RDP to the server in question, open the Reporting Services Configuration Manager and delete the encrypted data manually.
Without carrying out this step, I get the following error when I try to load up the report server interface of the new server:
The report server cannot open a connection to the report server
database. A connection to the database is required for all requests
and processing. (rsReportServerDatabaseUnavailable)
I'm trying to automate this step, so that it runs as part of a PowerShell script to remotely delete the encrypted data.
I am aware of 'rskeymgmt -d' but this prompts the user for input when run and has no force flag available to circumvent this additional input, rendering it unusable for running remotely as far as I can see:
C:\>rskeymgmt -d
All data will be lost. Are you sure you want to delete all encrypted data from
the report server database (Y/N)?
I've found a solutions to solving this problem. Calling RSKeyMgmt -d through a remote PowerShell session and piping the Y string to the call passes the parameter that RSKeyMgmt prompts the user for. This method is based on Som DT's post on backing up report server encryption keys
I've attached the full script I am using as part of my environment cloning process.
<#
.SYNOPSIS
Deletes encrypted content from a report server
.PARAMETER MachineName
The name of the machine that the report server resides on
.EXAMPLE
./Delete-EncryptedSsrsContent.ps1 -MachineName 'dev41pc123'
Deletes encrypted content from the 'dev41pc123' report server
#>
param([string]$MachineName = $(throw "MachineName parameter required, for command line usage of this script, type: 'get-help ./Delete-EncryptedSSRS.ps1 -examples'"))
trap [SystemException]{Write-Output "`n`nERROR: $_";exit 1}
Set-StrictMode -Version Latest
try
{
Write-Output "`nCreating remote session to the '$machineName' machine now..."
$session = New-PSsession -Computername $machineName
Invoke-Command -Session $Session -ScriptBlock {"Y" | RSKeyMgmt -d}
}
catch
{
Write-Output "`n`nERROR: $_"
}
finally
{
if ($Session)
{
Remove-PSSession $Session
}
}
This is a generalisation of ShaneC's solution, to support deletion of encrypted content on non default instances:
<#
.SYNOPSIS
Deletes encrypted content from a report server
.PARAMETER MachineName
The name of the machine that the report server resides on
.EXAMPLE
./Delete-EncryptedSsrsContent.ps1 -MachineName 'dev41pc123'
Deletes encrypted content from the default instance (MSSQLSERVER) of the 'dev41pc123' report server
.EXAMPLE
./Delete-EncryptedSsrsContent.ps1 -MachineName 'dev41pc123' -InstanceName 'NonDefault'
Deletes encrypted content from the specified non-default instance (e.g. NonDefault) of the 'dev41pc123' report server
#>
param(
[Parameter(Mandatory=$true)]
[string]$MachineName = $(throw "MachineName parameter required, for command line usage of this script, type: 'get-help ./Delete-EncryptedSSRS.ps1 -examples'"),
[Parameter(Mandatory=$false)]
[string]$InstanceName)
trap [SystemException]{Write-Output "`n`nERROR: $_";exit 1}
Set-StrictMode -Version Latest
try
{
Write-Output "`nCreating remote session to the '$MachineName' machine now..."
$session = New-PSsession -Computername $MachineName
if ([string]::IsNullOrEmpty($instanceName))
{
Invoke-Command -Session $Session -ScriptBlock {"Y" | RSKeyMgmt.exe -d}
}
else
{
Write-Output "`nDeleting all encrypted content from the $InstanceName instance on the $MachineName machine now...`n"
$command = """Y""| RSKeyMgmt.exe -d -i""" + $InstanceName + """"
Invoke-Command -Session $Session -ScriptBlock { Invoke-Expression $args[0] } -ArgumentList $command
Write-Output "`n"
}
}
catch
{
Write-Output "`n`nERROR: $_"
}
finally
{
if ($Session)
{
Remove-PSSession $Session
}
}

Remote Exchange Powershell session with variables

I have a beginner's knowledge in scripting and programming and have a set of PowerShell commands that I am having issues with figuring out how to turn it into a script.
I can successfully run the following remote commands from my Windows 7 machine by running the Exchange 2007 PowerShell console as my domain administrator account and then running the following commands to pass the commands to the Exchange 2013 hybrid server for use with Office 365:
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://hybridexch2013.contoso.com/PowerShell/ -Authentication Kerberos
Import-PSSession $Session
Enable-RemoteMailbox jame.doe#contoso.com -RemoteRoutingAddress jane.doe#contosoinc.mail.onmicrosoft.com
The more I look into this I don't know that I am making progress. See below for how my logic is working in my head on this. I understand this is incorrect and incomplete. I have commented out a function I had earlier but wasn't sure if I was doing it correct or if it was needed at all.
param($enableMailbox)
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://hybridexch2013.contoso.com/PowerShell/ -Authentication Kerberos
Import-PSSession $Session -AllowClobber
$fname = Read-Host "What is the user's first name?"
$lname = Read-Host "What is the user's last name?"
#function Func($enableMailbox)
#{
$enableMailbox = "Enable-RemoteMailbox $fname.$lname#contoso.com -RemoteRoutingAddress $fname.$lname#contosoinc.mail.onmicrosoft.com"
#}
#Func $enableMailbox
Write-Host $enableMailbox
I also find that if I manually run:
Enable-RemoteMailbox $fname.$lname#contoso.com -RemoteRoutingAddress $fname.$lname#contosoinc.mail.onmicrosoft.com
I get nothing. So I am not even understanding how you pass variables to the string to run the command correctly. Even if I run:
$fname = "Jane"
$lname = "Doe"
$enableMailbox = "Enable-RemoteMailbox $fname.$lname#contoso.com -RemoteRoutingAddress $fname.$lname#contosoinc.mail.onmicrosoft.com"
Write-Host $enableMailbox
I get no results.
I was trying to understand the param function using help from these pages: Powershell script with params *and* functions
Passing a variable to a powershell script via command line
https://devcentral.f5.com/blogs/us/powershell-abcs-p-is-for-parameters
http://www.experts-exchange.com/Programming/Languages/Scripting/Powershell/Q_27900846.html
But I am finding the param function difficult to understand and not sure I am even going in the right direction here. So far the only thing that seems to work is connecting to the PowerShell remotely.
Please help if I am am to be helped with this one and lack of my abilities here.
Param Function in short...
Function Write-Something
{
Param($InputText)
Write-Host $InputText
}
Write-Something Hello
Result is: Hello
Use Param Section to add Parameters to your Function like in the example above,
So for your Script:
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://hybridexch2013.contoso.com/PowerShell/ -Authentication Kerberos
Import-PSSession $Session -AllowClobber
Function Enable-MBX
{
Param($Fname,$Lname)
Enable-RemoteMailbox "$Fname $Lname" -RemoteRoutingAddress "$fname.$lname#contoso.mail.onmicrosoft.com"
}
Enable-MBX Jane Doe
I think you're just confused about Write-Host.
I'm not certain if you're trying to write the enable-remotemailbox to console or execute it. The code you have should work fine for writing to console (screen) but won't execute the command. To execute the command:
Enable-RemoteMailbox "$fname.$lname#contoso.com" -RemoteRoutingAddress "$fname.$lname#contosoinc.mail.onmicrosoft.com"
Anything inside of double-quotes will expand. Ex: "$fname" will expand to "Bob" if $fname is equal to "Bob". If you encapsulate the whole command in quotes in a variable though, the Write-Host will NOT execute the command. Write-Host is designed to write output to the screen so you'll just see the command in the console.
If you want to further expand, you can use the sub-string operator $(). Ex:
Write-Host "$($fname.length).$($lname.length)"
Comes back as "3.5" for "Bob" and "Smith".
To avoid expansion, use single quotes:
Write-Host '$($fname.length).$($lname.length)'
Writes "$($fname.length).$($lname.length)" to the console.
The following (similar to your code) without quotes: Write-Host $fname.$lname#contoso.com will try to pull the $lname#contoso.com Property of $fname which in this context doesn't make sense (doesn't exist). To elaborate, it would be equivalent to Write-Host $fname.($lname#contoso.com).

Resources