Edit: Added the whole converted c# to PowerShell with issue
I'm trying to convert MSDN C# code to PowerShell script.
Here's the MSDN link
I almost finished the conversion but I encounter some issues for my last line.
This is the complete error message: Exception calling "CreateDataDrivenSubscription" with "7" argument(s): "There was an error generating the XML document."
Below is the code snippet for the 7th argument in creating data driven subscription.
Here's the PowerShell script:
$Parameters | Add-Member -type NoteProperty -Name $EMPID.ParameterName -Value $EMPID.FieldAlias
$ReportYear = New-Object $ParameterValue
$ReportYear.Name = "ReportYear"
$ReportYear.Value = "2017"
$Parameters | Add-Member -type NoteProperty -Name $ReportYear.Name -Value $ReportYear.Value
$ReportMonth = New-Object $ParameterValue
$ReportMonth.Name = "ReportMonth"
$ReportMonth.Value = "6"
$Parameters | Add-Member -Type NoteProperty -Name $ReportMonth.Name -Value $ReportMonth.Value
$SubscriptionID = $objWebServerProxy.CreateDataDrivenSubscription($Report,$Settings,$arrDataRetrievalPlan,$Description,$EventType,$MatchData,$Parameters)
Here's the C# code
ParameterValueOrFieldReference[] parameters = new ParameterValueOrFieldReference[3];
ParameterFieldReference empID = new ParameterFieldReference(); // Data-driven.
empID.ParameterName = "EmpID";
empID.FieldAlias = "EmpID";
parameters[0] = empID;
ParameterValue reportYear = new ParameterValue();
reportYear.Name = "ReportYear";
reportYear.Value = "2004";
parameters[1] = reportYear;
ParameterValue reportMonth = new ParameterValue();
reportMonth.Name = "ReportMonth";
reportMonth.Value = "6"; // June
parameters[2] = reportMonth;
try
{
string subscriptionID = rs.CreateDataDrivenSubscription(
report, settings, dataRetrieval, description, eventType, matchData, parameters);
Can you tell me where did I miss on the conversion?
Here's my whole converted script.
$URI = "URI"
$objWebServerProxy = New-WebServiceProxy -Uri $URI -UseDefaultCredential -ErrorAction Stop
$Namespace = $objWebServerProxy.GetType().Namespace
$ExtensionSettigs = ($Namespace + '.ExtensionSettings')
$ParameterValueOrFieldReference = ($Namespace + '.ParameterValueOrFieldReference')
$ParameterFieldReference = ($Namespace + '.ParameterFieldReference')
$ParameterValue = ($Namespace + '.ParameterValue')
$Datasource = ($Namespace + '.DataSource')
$DataSourceDefinition = ($Namespace + '.DataSourceDefinition')
$Field = ($Namespace + '.Field')
$CredentialRetrievalEnum = ($Namespace + '.CredentialRetrievalEnum')
$DataSetDefinition = ($Namespace + '.DataSetDefinition')
$QueryDefinition = ($Namespace + '.QueryDefinition')
$DataSetDefinition = ($Namespace +'.DataSetDefinition')
$DataRetrievalPlan = ($Namespace+'.DataRetrievalPlan')
$ScheduleReference = ($Namespace+'.ScheduleReference')
$NameSharedSchedule="Mike_Test";
$NeverExpireSchedule= $objWebServerProxy.ListSchedules([System.Management.Automation.Language.NullString]::Value) | where {$_.Name -eq "$NameSharedSchedule"}
$NeverExpireScheduleID = $NeverExpireSchedule.scheduleid;
$NeverExpireDescription = $NeverExpireSchedule.Description;
$NeverExpireDefinition = $NeverExpireSchedule.Definition;
#Write-Host "Found Shared Schedule: '$NameSharedSchedule' with id $NeverExpireScheduleID and definition $NeverExpireDescription";
$NeverExpireScheduleRef =New-Object $ScheduleReference
$NeverExpireScheduleRef.ScheduleID=$NeverExpireScheduleID;
#$Report = "/ForMigration/Subscription_Test/SSRSRationalization_ExecutionLog_LastEightDays"
$Report = "/Gayatree/GTest/ExecutionLog_LastEightDays"
$Description = "My new Data Driven Subscription"
$Settings = New-Object $ExtensionSettigs
$Settings.Extension = "Report Server Email";
$ExtensionParams = New-Object $ParameterValueOrFieldReference
#$ExtensionParams.ParameterValueOrFieldReference ='8'
$To = New-Object $ParameterFieldReference
$To.ParameterName = "TO"
$To.FieldAlias = "Email"
$ExtensionParams | Add-Member -type NoteProperty -name $To.ParameterName -Value $To.FieldAlias
$ReplyTo = New-Object $ParameterValue
$ReplyTo.Name = "ReplyTo"
$ReplyTo.Value = "Email"
$ExtensionParams | Add-Member -type NoteProperty -name $ReplyTo.Name -Value $ReplyTo.Value
$IncludeReport = New-Object $ParameterValue
$IncludeReport.Name = "IncludeReport"
$IncludeReport.Value = $false
$ExtensionParams | Add-Member -type NoteProperty -name $IncludeReport.Name -Value $IncludeReport.Value
$RenderFormat = new-object $ParameterValue
$RenderFormat.Name = "ReportFormat";
$RenderFormat.Value = "HTML4.0"
$ExtensionParams | Add-Member -type NoteProperty -name $RenderFormat.Name -Value $RenderFormat.Value
$Priority = New-Object $ParameterValue
$Priority.Name = "Priority"
$Priority.Value = "Normal"
$ExtensionParams | Add-Member -type NoteProperty -name $Priority.Name -Value $Priority.Value
$Subject = New-Object $ParameterValue
$Subject.Name = "Subject"
$Subject.Value = "Your sales report"
$ExtensionParams | Add-Member -type NoteProperty -name $Subject.Name -Value $Subject.Value
$Comment = New-Object $ParameterValue
$Comment.Name = "Comment"
$Comment.Value = "Here is the link to your report."
$ExtensionParams | Add-Member -type NoteProperty -name $Comment.Name -Value $Comment.Value
$IncludeLink = New-Object $ParameterValue
$IncludeLink.Name = "IncludeLink";
$IncludeLink.Value = $true
$ExtensionParams | Add-Member -Type NoteProperty -name $IncludeLink.Name -Value $IncludeLink.Value
$Settings.ParameterValues = $ExtensionParams
$DSName = New-Object $Datasource
$DSName.Name = "Mike_Test"
<#
$DSDefinition = New-Object $DataSourceDefinition
$CredentialRetrieval = New-Object $CredentialRetrievalEnum
$CredentialRetrieval.value__ = 1
$DSDefinition.ConnectString = "Data source = server;Initial Catalog = ReportServer"
$DSDefinition.CredentialRetrieval = $CredentialRetrieval
$DSDefinition.Enabled = $true
$DSDefinition.EnabledSpecified = $true
$DSDefinition.Extension = "SQL"
$DSDefinition.ImpersonateUserSpecified = $false
$DSDefinition.UserName = "Username"
$DSDefinition.Password = "Password"
#>
$DS = $objWebServerProxy.ListChildren('/',$false)|Where-Object {$_.TypeName -eq "DataSource"}
foreach($DSS in $DS){
$anotherPass = $DSS.path
$another = $objWebServerProxy.GetDataSourceContents("$anotherPass")
$another.Password = "TestPass"
}
$another
$DSName.Item = $another
$FieldList = New-Object $Field
$FieldList.Name = "EmailAddress"
$FieldList.Alias = "EmailAddress"
$FieldList | Add-Member -Type NoteProperty -name $FieldList.Name -Value $FieldList.Alias
$FieldList.Name = "EmpID"
$FieldList.Alias = "EmpID"
$FieldList | Add-Member -Type NoteProperty -name $FieldList.Name -Value $FieldList.Alias
$DataSetDef = New-Object $DataSetDefinition
$DataSetDef.AccentSensitivitySpecified = $false
$DataSetDef.CaseSensitivitySpecified = $false
$DataSetDef.KanatypeSensitivitySpecified = $false
$DataSetDef.WidthSensitivitySpecified = $false
$DataSetDef.Fields = $FieldList
$arrQueryDefinition = New-Object $QueryDefinition
$arrQueryDefinition.CommandText = "Select getdate()"
$arrQueryDefinition.CommandType = "Text"
$arrQueryDefinition.Timeout = '45'
$arrQueryDefinition.TimeoutSpecified = $true
$DataSetDef.Query = $arrQueryDefinition
$Results = New-Object $DataSetDefinition
$Bool = $true
$Name = "Parameter"
$DSDefinition
$DataSetDef
$DSName
$Results = $objWebServerProxy.PrepareQuery($DSName,$DataSetDef,[ref]$Bool,[ref]$Name)
$arrDataRetrievalPlan = New-Object $DataRetrievalPlan
$arrDataRetrievalPlan.DataSet = $Results
$arrDataRetrievalPlan.Item = $another
$EventType = "TimedSubscription";
$MatchData = $NeverExpireScheduleID
$Parameters = New-Object $ParameterValueOrFieldReference
#
$EMPID = New-Object $ParameterFieldReference
$EMPID.ParameterName = "EmpID"
$EMPID.FieldAlias = "EmpID"
$Parameters | Add-Member -type NoteProperty -Name $EMPID.ParameterName -Value $EMPID.FieldAlias
$ReportYear = New-Object $ParameterValue
$ReportYear.Name = "ReportYear"
$ReportYear.Value = "2017"
$Parameters | Add-Member -type NoteProperty -Name $ReportYear.Name -Value $ReportYear.Value
$ReportMonth = New-Object $ParameterValue
$ReportMonth.Name = "ReportMonth"
$ReportMonth.Value = "6"
$Parameters | Add-Member -Type NoteProperty -Name $ReportMonth.Name -Value $ReportMonth.Value
$SubscriptionID = $objWebServerProxy.CreateDataDrivenSubscription($Report,$Settings,$arrDataRetrievalPlan,$Description,$EventType,$MatchData,$Parameters)
I'm not sure if the way you're creating the ParameterValue instances works - I can't tell for sure since the $ParameterValue declaration is missing, but chances are this causes the problem.
You might want to try something more along the lines of this:
$reportServerUri = "http://localhost/reportserver/ReportService2010.asmx?wsdl"
$rs = New-WebServiceProxy -Uri $reportServerUri -UseDefaultCredential -Namespace "SSRS"
# Note the difference, here we use the type generated when creating the webservice proxy:
$ReportYear = New-Object SSRS.ParameterValue
$ReportYear.Name = "ReportYear"
$ReportYear.Value = "2017"
See my blog post here for a quick tutorial.
Edit
To pinpoint which argument of CreateDataDrivenSubscription the error is, try substituting one or more arguments with $null - sure it might be invalid according to the method's documentation, but the null checks only occur once the call has been successfully sent to the server and deserialized.
In other words, if substituting the $Parameters argument with $null does not throw the "error generating XML document", then the error is in the $Parameters argument:
$SubscriptionID = $objWebServerProxy.CreateDataDrivenSubscription($Report,$Settings,
$arrDataRetrievalPlan,$Description,$EventType,$MatchData,$null)
Related
I have a need to run PowerShell scripts from C# application. I like using method AddScript for this. And it works quite nice. However, it does not seem to work as expected when I added parameters to script with method AddParameters.
Here is test payload (PowerShell):
param ([string]$Arg1, [string]$Arg2, [switch]$ArgParamless)
$filename = "payload_with_params.txt"
$filepath = $env:temp
$fullpath = Join-Path -Path $filepath -ChildPath $filename
$dt = Get-Date -Format "yyyy.MM.dd HH:mm:ss"
$val = $dt+' '+$Arg1+' '+$Arg2+' '+$ArgParamless
Add-Content -Path $fullpath -Value "$val"
It works just fine if I push it from PS like this:
.\payload_with_params.ps1 -Arg1 "Bla 1" -Arg2 "Bla 2" -ArgParamless
Result:
2023.01.19 16:58:10 Bla 1 Bla 2 True
The C# code (oversimplified):
string command = File.ReadAllText(pathToPS1);
List<CommandParameter> paramList = new List<CommandParameter>();
paramList.Add(new CommandParameter("Arg1", "Bla 1"));
paramList.Add(new CommandParameter("Arg2", "Bla 2"));
paramList.Add(new CommandParameter("ArgParamless"));
using (PowerShell ps = PowerShell.Create())
{
//Adding script file content to object
ps.AddScript(command);
if (paramList != null)
{
if (paramList.Count > 0)
{
//Adding Params to object;
ps.AddParameters(paramList);
}
}
//Launching
ps.Invoke();
}
And the result:
2023.01.19 16:54:00 System.Management.Automation.Runspaces.CommandParameter System.Management.Automation.Runspaces.CommandParameter False
So.. it's not working as I expected. How should I supply parameters to script?
For [switch] parameters, you'll want to bind a bool - PowerShell will interpret true as "Present" and false as "Absent":
paramList.Add(new CommandParameter("ArgParamless", true));
Well, it turns out AddParameter(CommandParameter) approach doesn't work.
This approach is working:
string command = File.ReadAllText(pathToPS1);
using (PowerShell ps = PowerShell.Create())
{
//Adding script file content to object
ps.AddScript(command);
if (paramList != null)
{
if (paramList.Count > 0)
{
//Adding Params to object;
ps.AddArgument("-Arg1 XXXXXX");
}
}
//Launching
ps.Invoke();
}
On PowerShell end this arguments can be extracted for usage from $args array:
$arglist = $args -join " "
Even better approach using hashtable:
string command = File.ReadAllText(pathToPS1);
using (PowerShell ps = PowerShell.Create())
{
//Adding script file content to object
ps.AddScript(command);
if (paramList != null)
{
if (paramList.Count > 0)
{
//Adding Params to object;
var hashtable = new Hashtable {
{ "Arg1", "XXXXXX" },
{ "Arg2", "YYYYYY" },
{ "ArgParamless", true }
};
ps.AddArgument(hashtable);
}
}
//Launching
ps.Invoke();
}
And that's what you do on PS side to use it:
function Wrapper-Test ([string]$Arg1, [string]$Arg2, [switch]$ArgParamless) {
$Result = $Args1+' '+$Args2+' '+$ArgParamless
return $Result
}
$MyArgs = "";
$MyArg = $args[0]
$MyArgs = Wrapper-Test #MyArg;
$filename = "payload_with_params.txt"
$filepath = $env:temp
$fullpath = Join-Path -Path $filepath -ChildPath $filename
$dt = Get-Date -Format "yyyy.MM.dd HH:mm:ss"
$arglist = $args -join " "
$val = $dt + " " + $MyArgs
Add-Content -Path $fullpath -Value "$val"
I need to make a system for domain change and it is necessary to execute this code via C #, but I have tried everything and I cannot.
To run the script in PowerShell, you must initialize it as an administrator. In PowerShell, it works without problems.
Code in Power Shell:
$domain = "NameDomain"`enter code here`
$password = "pwd" | ConvertTo-SecureString -asPlainText -Force
$username = "$domain\User"
$credential = New-Object System.Management.Automation.PSCredential($username,$password)
Add-Computer -DomainName $domain -Credential $credential -Restart -Force
Code in C#;
var scriptfile = #"$domain = ""dominio""; $password = ""psw"" | ConvertTo-SecureString -asPlainText -Force; $username = ""domain\user""; $credential = New-Object System.Management.Automation.PSCredential($username,$password); Add-Computer -DomainName $domain -Credential $credential -Restart -Force";
Method used:
private string RunScript(string script)
{
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pip = runspace.CreatePipeline();
pip.Commands.AddScript(script);
pip.Commands.Add("Out-String");
Collection<PSObject> results = pip.Invoke();
runspace.Close();
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject pSObject in results)
stringBuilder.AppendLine(pSObject.ToString());
return stringBuilder.ToString();
}
I've been searching the solution of this problem for weeks now and still blocked...
I need to use the program "quser" in powershell but in my C# program.
If I run "quser" just in the powershell console I have a result.
But when I execute a powershell script with "quser", it returns nothing... That's weird.
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
String script = "$re = '(\\S+)\\s+?(\\S*)\\s+?(\\d+)\\s+(\\S+)\\s+(\\S+)\\s+(\\d+\\/\\d+\\/\\d+\\s+\\d+:\\d+)'\n"
+ "query user /server:"+machine+" | Where-Object { $_ -match $re } | ForEach-Object {\n"
+ "New-Object -Type PSCustomObject -Property #{"
+ "'Username' = $matches[1]\n"
+ "'LogonTime' = $matches[6]\n"
+ "}\n"
+ "} | Select-Object Username, LogonTime | ForEach-Object { Write-Output (\"{0} is connected from {1}\" -f $_.Username, $_.LogonTime) }";
ps.AddScript(script);
Collection<PSObject> result = ps.Invoke();
ps.Dispose();
runspace.Close();
runspace.Dispose();
Console.WriteLine(result.Count);
The result of the ps.Invoke() is empty.
But when I run this code from a powershell console it works.
Also another weird thing, it works in remote powershell :
String script = "$re = '(\\S+)\\s+?(\\S*)\\s+?(\\d+)\\s+(\\S+)\\s+(\\S+)\\s+(\\d+\\/\\d+\\/\\d+\\s+\\d+:\\d+)'\n"
+ "query user | Where-Object { $_ -match $re } | ForEach-Object {\n"
+ "New-Object -Type PSCustomObject -Property #{"
+ "'Username' = $matches[1]\n"
+ "'LogonTime' = $matches[6]\n"
+ "}\n"
+ "} | Select-Object Username, LogonTime | ForEach-Object { Write-Output (\"{0} is connected from {1}\" -f $_.Username, $_.LogonTime) }";
string shellUri = "http://schemas.microsoft.com/powershell/Microsoft.PowerShell";
System.Security.SecureString sString = new System.Security.SecureString();
foreach (char passwordChar in password.ToCharArray())
{
sString.AppendChar(passwordChar);
}
PSCredential credential = new PSCredential(username, sString);
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(false, machine, 5985, "/wsman", shellUri, credential);
List<String> scriptOutput = new List<String>();
using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
runspace.Open();
Pipeline pipe = runspace.CreatePipeline();
pipe.Commands.AddScript(script);
Collection<PSObject> result = pipe.Invoke();
foreach (PSObject line in result)
{
scriptOutput.Add(line.ToString());
}
pipe.Dispose();
runspace.Close();
}
foreach(String line in scriptOutput)
{
Console.WriteLine(line);
}
It returns the connected user.
The fact is that I don't want to logged into the machine in order to see the conncted users. (because it works in the powershell console)
If someone could help me please.
Thanks.
I am trying to run a powershell script in c#
here is the first test script
param(
[string] $computer,
[string] $password
)
out-file -filepath C:\File\parameter.txt -inputobject $computer -encoding ASCII -width 50 -Append
out-file -filepath C:\File\params.txt -inputobject $password -encoding ASCII -width 50 -Append
out-file -filepath C:\File\Sys32.txt -inputobject $password -encoding ASCII -width 50 -Append
and here is my C# supposed to run the powershellscript
private void testRunningPowershell()
{
string mypass = gettingPass();
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
runspace.SessionStateProxy.Path.SetLocation("C:\\Users\\robert\\Desktop\\Titanium\\");
RunspaceInvoke runSpaceInvoker = new RunspaceInvoke(runspace);
//runSpaceInvoker.Invoke("Set-ExecutionPolicy Unrestricted");
// create a pipeline and feed it the script text (AddScript method) or use the filePath (Add method)
using (Pipeline pipeline = runspace.CreatePipeline())
{
Command command = new Command(#"C:\Users\robert\Desktop\Titanium\Titanium2.ps1");
dictionaryParams.Remove("FriendlyName");
foreach (var item in dictionaryParams)
{
if (item.Key == (string)comboBoxScreen.SelectedItem)
{
CommandParameter testParam = new CommandParameter(null, item.Value);
CommandParameter testParam2 = new CommandParameter(null, mypass);
command.Parameters.Add(null, testParam);
command.Parameters.Add(null, testParam2);
}
}
pipeline.Commands.Add(command);
var results = pipeline.Invoke();
ReturnInfo ri = new ReturnInfo();
foreach (PSObject p in results)
{
Hashtable ht = p.ImmediateBaseObject as Hashtable;
ri.ReturnText = (string)ht["ComputerName"];
ri.ReturnText = (string)ht["password"];
}
runspace.Close();
}
}
}
my purpose is to test if the cmdlet is run with the right parameters
I've got a windows form app that allow the user to choose the parameter
I would like to get my parameter value written in Text File (.txt)
instead I am getting this
System.Management.Automation.Runspaces.CommandParameter
instead of the parameter's value choosen
Hello stackoverflow friends!
I have a Powershell script I'm working on where I am trying to do the following:
Select an Excel xlsx file with existing worksheets with headers only
Select a text file
Create a temporary CSV file from the text file and add headers to match the Excel file
Copy the information from the CSV file into a worksheet in the Excel file
Save/Quit
I've got everything I need working up to using the Range aspects of the Excel objects. When attempting to Copy data from the CSV file instantiated as a COM object, then Activating the xlsx file, I am getting an error stating
Exception calling "Paste" with "1" argument(s): "Paste method of
Worksheet class failed" At line:1 char:1
$Script:ExcelWorkSheet.Paste($tempRange)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : NotSpecified: (:) [], MethodInvocationException
FullyQualifiedErrorId : ComMethodTargetInvocation
Below is my code thus far. Any help whatsoever would be gratefully appreciated, as I'm at a loss:
BEGIN
{
Function Set-ScriptVars()
{
Add-Type -AssemblyName System.Windows.Forms
}
Function Select-File($FileType)
{
## Select file via selection dialog
do {
if($FileType -eq "xlsx")
{
Write-Host "`nPlease select the Excel file to import in the dialog"
}
elseif($FileType -eq "txt")
{
Write-Host "`nPlease select the Prescan or Postscan text file to import in the dialog"
}
Start-Sleep -Seconds 1
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property #{InitialDirectory = [Environment]::GetFolderPath('Desktop')}
[void]$FileBrowser.ShowDialog()
Write-Host "`nFile selected: " -NoNewline
Write-Host $FileBrowser.FileNames -ForegroundColor Yellow
$FileName = $FileBrowser.FileName
if ($FileName.EndsWith(".$FileType"))
{
$selectionValid = $True
}
else
{
Write-Host "The file selected is not a .$FileType file."
Write-Host "Restarting file selection loop."
$selectionValid = $False
}
} until ($selectionValid -eq $True)
if($FileType -eq "txt")
{
$Script:TextFile = $FileName
$Script:TextParentPath = (Get-Item $FileName).Directory.FullName
}
elseif($FileType -eq "xlsx")
{
$Script:ExcelFile = $FileName
$Script:ExcelParentPath = (Get-Item $FileName).Directory.FullName
}
}
Function Open-Excel($Sheet)
{
$ActiveSheet = $Sheet
$ExcelPath = $Script:ExcelFile
$Script:Excel = New-Object -ComObject Excel.Application
$Script:Excel.Visible = $True
$Script:Excel.UserControl = $False
$Script:Excel.Interactive = $False
$Script:Excel.DisplayAlerts = $False
$Script:ExcelWorkBook = $Script:Excel.Workbooks.Open($ExcelPath)
$Script:ExcelWorkSheet = $Script:Excel.WorkSheets.item($ActiveSheet)
$Script:ExcelWorkSheet.Activate()
}
Function Get-TextContent()
{
$Script:TextContent = Get-Content $Script:TextFile
}
Function Copy-TextData()
{
# create a random file name
$randomInt = #(0001..9999) | Get-Random
$tempCSV = Import-CSV $Script:TextFile -Header "Server","Role","Type","Object","Path"
$tempCSV | Export-CSV -Path $ENV:USERPROFILE\Desktop\tempCSV_$randomInt.csv -NoTypeInformation
$tempCSVPath = "$ENV:USERPROFILE\Desktop\tempCSV_$randomInt.csv"
$tempCSVName = "tempCSV_$randomInt"
# create a temporary file to copy from
$TempExcel = New-Object -ComObject Excel.Application
$TempExcel.Visible = $True
$TempWorkBook = $TempExcel.WorkBooks.Open($tempCSVPath)
$TempWorkSheet = $TempWorkBook.WorkSheets.Item($tempCSVName)
$tempRange = $TempWorkSheet.Range("A2:E2").UsedRange
$tempRange.Copy() | Out-Null
$Script:ExcelWorkSheet.Activate()
$Script:ExcelWorkSheet.Range("A2:E2").EntireColumn
$Script:ExcelWorkSheet.Paste($tempRange)
$Script:ExcelWorkBook.Save()
$Script:Excel.Quit()
[gc]::Collect()
[gc]::WaitForPendingFinalizers()
Write-Host "Break"
}
}
PROCESS
{
Set-ScriptVars
Select-File -FileType "xlsx"
Select-File -FileType "txt"
if($Script:TextFile -match "Prescan")
{
Open-Excel -Sheet "Prescan"
}
elseif($Script:TextFile -match "Postscan")
{
Open-Excel -Sheet "Postscan"
}
Get-TextContent
Copy-TextData
}
END
{
}
In this case, utilizing VB macros is not an option.
If such a task is more easily accomplished by leveraging a .NET assembly or dropping in C# code in a #' '# format, I'm all ears!
After spending a great deal of time, I finally came to a workable solution.
For anyone who may come across this through a search engine in the future, I hope the code below helps!
BEGIN
{
Function Set-ScriptVars()
{
Add-Type -AssemblyName System.Windows.Forms
}
Function Select-File($FileType)
{
## Select file via selection dialog
do {
if($FileType -eq "xlsx")
{
Write-Host "`nPlease select the Excel file to import in the dialog"
}
elseif($FileType -eq "txt")
{
Write-Host "`nPlease select the Prescan or Postscan text file to import in the dialog"
}
Start-Sleep -Seconds 1
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property #{InitialDirectory = [Environment]::GetFolderPath('Desktop')}
[void]$FileBrowser.ShowDialog()
Write-Host "`nFile selected: " -NoNewline
Write-Host $FileBrowser.FileNames -ForegroundColor Yellow
$FileName = $FileBrowser.FileName
if ($FileName.EndsWith(".$FileType"))
{
$selectionValid = $True
}
else
{
Write-Host "The file selected is not a .$FileType file."
Write-Host "Restarting file selection loop."
$selectionValid = $False
}
} until ($selectionValid -eq $True)
if($FileType -eq "txt")
{
$Script:TextFile = $FileName
$Script:TextParentPath = (Get-Item $FileName).Directory.FullName
}
elseif($FileType -eq "xlsx")
{
$Script:ExcelFile = $FileName
$Script:ExcelParentPath = (Get-Item $FileName).Directory.FullName
}
}
Function Open-Excel($Sheet)
{
$ExcelPath = $Script:ExcelFile
$Script:Excel = New-Object -ComObject Excel.Application
$Script:Excel.Visible = $False
$Script:Excel.UserControl = $False
$Script:Excel.Interactive = $True
$Script:Excel.DisplayAlerts = $False
$Script:ExcelWorkBook = $Script:Excel.Workbooks.Open($ExcelPath)
$Script:ExcelWorkSheet = $Script:Excel.WorkSheets.item($Sheet)
$Script:ExcelWorkSheet.Activate()
}
Function Get-TextContent()
{
$Script:TextContent = Get-Content $Script:TextFile
}
function Release-Ref ($ref) {
([System.Runtime.InteropServices.Marshal]::ReleaseComObject(
[System.__ComObject]$ref) -gt 0) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
Function Copy-TextData()
{
# create a CSV from the scan data
$Script:TextContent = Get-Content $Script:TextFile
$data = #()
$row = New-Object PSObject
foreach($line in $Script:TextContent)
{
if($line -eq "CSV was validated without errors." -or $line -eq "")
{
Out-Null
}
else
{
$i = 0
$values = $line -split ","
$result = [PSCustomObject]#{Server=$values[0];`
Role=$values[1];`
Object=$values[2];`
Type=$values[3];`
Path=$values[4]
}
[Array]$results = $results + $result
}
}
$csvName = "scanData_" + "$(#(000..999) | Get-Random)"
$results | Export-CSV -Path "$ENV:USERPROFILE\Desktop\$csvName.csv" -NoTypeInformation
$csvPath = $(Get-Item $ENV:USERPROFILE\Desktop\$csvName.csv).VersionInfo.FileName
# Remove header generated by hashtable
# and skip the next two lines
$tempContent = Get-Content $csvPath
$replacementContent = $tempContent | Select -Skip 3
Set-Content $csvPath -Value $replacementContent
# create temporary workbook and save as xlsx
$tempXL = New-Object -ComObject Excel.Application
$tempXL.Visible = $False
$tempXL.UserControl = $False
$tempXL.Interactive = $True
$tempXL.DisplayAlerts = $False
$tempWB = $tempXL.WorkBooks.Open("$csvPath")
$tempWS = $tempWB.WorkSheets
$convertedName = $csvPath.Replace(".csv",".xlsx")
$tempWB.SaveAs($convertedName,1)
$tempWB.Saved = $True
$tempRange = $tempWB.Worksheets.Item(1).UsedRange
$tempRange.Copy()
if($Script:logSelection -eq "Prescan")
{
$permRange = $Script:ExcelWorkBook.Worksheets.Item(2)
}
else
{
$permRange = $Script:ExcelWorkBook.Worksheets.Item(3)
}
$subRange = $permRange.Range("A2","E2")
$permRange.Paste($subRange)
$permRange.Columns.AutoFit()
$Script:ExcelWorkBook.Save()
$Script:ExcelWorkBook.Saved = $True
$Script:Excel.Quit()
$tempWB.Save()
$tempWB.Saved = $True
$tempXL.Quit()
Release-Ref($Script:ExcelWorkSheet)
Release-Ref($tempWS)
Release-Ref($Script:ExcelWorkBook)
Release-Ref($tempWB)
Release-Ref($Script:Excel)
Release-Ref($tempXL)
Remove-Item $csvPath -Force
Get-Item $convertedName | Remove-Item -Force
}
Function Prompt-ReRun
{
do
{
$openChoice = Read-Host "`nRun again? (y/n)"
$openChoice = $openChoice.ToLower()
} until($openChoice -eq "y" -or $openChoice -eq "n")
if($openChoice -ne "y" -and $openChoice -ne "n")
{
Write-Host "Invalid entry"
}
elseif($openChoice -eq "y")
{
Run-Selection
}
else
{
Out-Null
}
}
Function Run-Selection
{
Select-File -FileType "xlsx"
Select-File -FileType "txt"
if($Script:TextFile -match "Prescan")
{
Open-Excel -Sheet "Prescan"
$Script:logSelection = "Prescan"
}
elseif($Script:TextFile -match "Postscan")
{
Open-Excel -Sheet "Postscan"
$Script:logSelection = "Postscan"
}
Get-TextContent
Copy-TextData
Prompt-ReRun
}
}
PROCESS
{
Set-ScriptVars
Run-Selection
}
END
{
}