I have a simple DotNet DLL like this
namespace ClassLibrary1
{
public class Class1
{
public static void Test()
{
Process.Start("CMD.exe", "/C calc");
}
}
}
When I try to load this DLL with powershell
$Path = "c:\\test\\ClassLibrary1.dll";
$Namespace = "ClassLibrary1";
$ClassName = "Class1";
$Method = "Test";
$Arguments = $null
$Full_Path = [System.IO.Path]::GetFullPath($Path);
$AssemblyName = [System.Reflection.AssemblyName]::GetAssemblyName($Full_Path)
$Full_Class_Name = "$Namespace.$ClassName"
$Type_Name = "$Full_Class_Name, $($AssemblyName.FullName)"
$Type = [System.Type]::GetType($Type_Name)
$MethodInfo = $Type.GetMethod($Method)
$MethodInfo.Invoke($null, $Arguments)
It does not work, because [System.Type]::GetType($Type_Name) returned $null
Any ideas?
Use Add-Type -Path to load your assembly.
After loading, to get a reference to that assembly's [ClassLibrary1.Class1] type as a [Type] instance (to use for reflection) via a string variable, simply cast to [Type].
The following corrected and annotated version of your code demonstrates the approach:
# Compile the C# source code to assembly .\ClassLibrary1.dll
Add-Type -TypeDefinition #'
namespace ClassLibrary1
{
public class Class1
{
public static void Test()
{
System.Diagnostics.Process.Start("CMD.exe", "/C calc");
}
}
}
'# -OutputAssembly .\ClassLibrary1.dll
# Define the path to the assembly. Do NOT use "\\" as the path separator.
# PowerShell doesn't use "\" as the escape character.
$Path = ".\ClassLibrary1.dll"
$Namespace = "ClassLibrary1"
$ClassName = "Class1"
$Method = "Test"
$Arguments = $null
# Load the assembly by its filesystem path, using the Add-Type cmdlet.
# Use of relative paths works.
Add-Type -Path $Path
$Full_Class_Name = "$Namespace.$ClassName"
# To get type [ClassLibrary1.Class1] by its full name as a string,
# simply cast to [type]
$Type = [type] $Full_Class_Name
$MethodInfo = $Type.GetMethod($Method)
$MethodInfo.Invoke($null, $Arguments)
As for what you tried:
As PetSerAl points out, [System.Type]::GetType() can only find a given type if:
its assembly is already loaded
its assembly can be located via standard assembly resolution, as detailed here, which involves many complicated rules, the only two of which likely apply to your scenario is if you're trying to reference a built-in type from the mscorlib assembly, or an assembly located in the GAC (Global Assembly Cache).
By definition, only strongly-named assemblies - those signed with a private key matching the public key mentioned in the assembly's full name - can be placed in the GAC.
While you could have called [System.Reflection.Assembly]::LoadFile($Full_Path) first in order to load the assembly via its filesystem path, after which [System.Type]::GetType($Type_Name) would have succeeded, it is ultimately simpler - and more PowerShell-idiomatic - to use Add-Type -Path to load the assembly (which has the added advantage of not requiring a full (absolute) file path), and, once loaded, to use [Type] with just the type's full name (no reference to the assembly needed anymore).
I have created a windows service using TOPSHELF dlls but I want to make it be able to receive parameters after installing it.
Say my folderpath is the place from where the service will read the file.
Here is my Start method.
public void Start()
{
_log.Info("SampleService is Started");
_timer.AutoReset = true;
_timer.Enabled = true;
_timer.Start();
//String folderpath I want to use this as a start parameter.
GetAndConvertFileIntoXML(folderPath);
}
Oliver has a great answer if you wanted to go down that path. It's not something I expect to see in Topshelf (even if the patch shows up in the mail).
We don't have a way to do this in Topshelf because it's complicated to understand the context you use. We believe you should use app.config to manage this instead of command line parameters.
Let me explain the experience problem I haven't figured out: service install --myparam=one - Great! We modify the IMAGE_PATH like Oliver's patch does. Now, what should it be if you install an update with just service install? Should we try and keep that parameter? What if it's tied to the instance name and you just forgot it? In addition, there's no visibility into what arguments are set for a given service.
If someone helps me come up with a way to make this experience clear to users, I'd be apt to ship it with Topshelf. In the mean time, our guidance is use app.config.
When you manually install a windows service by using the command line you can provide additional arguments that should be added to your application start easily:
sc create MyService binPath="notepad d:\myFile.txt"
Unfortunately doesn't Topshelf support this. So i took the sources and added that feature on my own. I sent the needed patch to the project (not by pull request, but by mail) but they never answered me or built the feature into the code.
After applying that patch (see bottom) you get a new method SetArguments() which let's define you additional parameters that your service should append to the exe path that's been called at start of your service. If you like to provide this argument also to the application when you call it with the install keyword, then it gets a little bit complicated, but it works. First the code needed to forward the desired command line argument to the service installer:
var host = HostFactory.New(x =>
{
x.AddCommandLineDefinition("configuration", filename =>
{
configFileName = CreateFullPathName(filename);
x.SetArguments("-configuration \"" + configFileName + "\"");
});
...
});
If you now call your program with the command line
MyServiceApplication install -configuration ".\Some Sub Folder\My File.txt"
you can see within the services.msc that under path to executable of your service the parameter has been added and will be filled when the service gets started.
Patch file
Index: src/Topshelf/Runtime/HostSettings.cs
===================================================================
--- src/Topshelf/Runtime/HostSettings.cs (original)
+++ src/Topshelf/Runtime/HostSettings.cs (add SetArguments)
## -38,6 +38,11 ##
string InstanceName { get; }
/// <summary>
+ /// The additional arguments that should be appended when the service is installed
+ /// </summary>
+ string Arguments { get; }
+
+ /// <summary>
/// Returns the Windows service name, including the instance name, which is registered with the SCM Example: myservice$bob
/// </summary>
/// <returns> </returns>
Index: src/Topshelf/Runtime/Windows/HostServiceInstaller.cs
===================================================================
--- src/Topshelf/Runtime/Windows/HostServiceInstaller.cs (original)
+++ src/Topshelf/Runtime/Windows/HostServiceInstaller.cs (add SetArguments)
## -114,6 +114,9 ##
if (!string.IsNullOrEmpty(settings.Name))
arguments += string.Format(" -servicename \"{0}\"", settings.Name);
+ if (!string.IsNullOrEmpty(settings.Arguments))
+ arguments += " " + settings.Arguments;
+
return new HostInstaller(settings, arguments, installers);
}
Index: src/Topshelf/Runtime/Windows/WindowsHostSettings.cs
===================================================================
--- src/Topshelf/Runtime/Windows/WindowsHostSettings.cs (original)
+++ src/Topshelf/Runtime/Windows/WindowsHostSettings.cs (add SetArguments)
## -1,14 +1,14 ##
// Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al.
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
-// this file except in compliance with the License. You may obtain a copy of the
-// License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+// this file except in compliance with the License. You may obtain a copy of the
+// License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
namespace Topshelf.Runtime.Windows
{
## -19,8 +19,8 ##
HostSettings
{
public const string InstanceSeparator = "$";
- string _description;
- string _displayName;
+ private string _description;
+ private string _displayName;
/// <summary>
/// Creates a new WindowsServiceDescription using empty strings for the properties. The class is required to have names by the consumers.
## -49,6 +49,8 ##
_description = "";
}
+ public string Arguments { get; set; }
+
public string Name { get; set; }
public string DisplayName
## -68,7 +70,6 ##
set { _displayName = value; }
}
-
public string Description
{
get
## -80,7 +81,6 ##
set { _description = value; }
}
-
public string InstanceName { get; set; }
public string ServiceName
Index: src/Topshelf/Topshelf.csproj
===================================================================
--- src/Topshelf/Topshelf.csproj (original)
+++ src/Topshelf/Topshelf.csproj (add SetArguments)
## -112,6 +112,7 ##
<Compile Include="Configuration\HostConfigurators\SudoConfigurator.cs" />
<Compile Include="Configuration\HostConfigurators\UninstallHostConfiguratorAction.cs" />
<Compile Include="Configuration\HostConfigurators\UnknownCommandLineOptionHostConfigurator.cs" />
+ <Compile Include="Configuration\Options\ArgumentsOption.cs" />
<Compile Include="Configuration\Options\AutostartOption.cs" />
<Compile Include="Configuration\Options\DelayedOption.cs" />
<Compile Include="Configuration\Options\DisabledOption.cs" />
## -221,6 +222,9 ##
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
+ <ItemGroup>
+ <None Include="Internals\README.md" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Index: src/Topshelf/Hosts/InstallHost.cs
===================================================================
--- src/Topshelf/Hosts/InstallHost.cs (original)
+++ src/Topshelf/Hosts/InstallHost.cs (add SetArguments)
## -139,6 +139,11 ##
_dependencies = dependencies;
}
+ public string Arguments
+ {
+ get { return _settings.Arguments; }
+ }
+
public string Name
{
get { return _settings.Name; }
Index: src/Topshelf/Configuration/HostConfigurators/CommandLineParserOptions.cs
===================================================================
--- src/Topshelf/Configuration/HostConfigurators/CommandLineParserOptions.cs (original)
+++ src/Topshelf/Configuration/HostConfigurators/CommandLineParserOptions.cs (add SetArguments)
## -61,7 +61,9 ##
.Or(from disp in x.Definition("displayname")
select (Option)new DisplayNameOption(disp.Value))
.Or(from instance in x.Definition("instance")
- select (Option)new InstanceOption(instance.Value)));
+ select (Option)new InstanceOption(instance.Value))
+ .Or(from instance in x.Definition("arguments")
+ select (Option)new ArgumentsOption(instance.Value)));
}
internal static void AddUnknownOptions(ICommandLineElementParser<Option> x)
Index: src/Topshelf/Configuration/HostConfigurators/HostConfiguratorImpl.cs
===================================================================
--- src/Topshelf/Configuration/HostConfigurators/HostConfiguratorImpl.cs (original)
+++ src/Topshelf/Configuration/HostConfigurators/HostConfiguratorImpl.cs (add SetArguments)
## -64,7 +64,7 ##
yield return this.Failure("Name", "must be specified and not empty");
else
{
- var disallowed = new[] {' ', '\t', '\r', '\n', '\\', '/'};
+ var disallowed = new[] { ' ', '\t', '\r', '\n', '\\', '/' };
if (_settings.Name.IndexOfAny(disallowed) >= 0)
yield return this.Failure("Name", "must not contain whitespace, '/', or '\\' characters");
}
## -86,6 +86,11 ##
yield return this.Success("ServiceName", _settings.ServiceName);
}
+ public void SetArguments(string arguments)
+ {
+ _settings.Arguments = arguments;
+ }
+
public void SetDisplayName(string name)
{
_settings.DisplayName = name;
Index: src/Topshelf/Configuration/HostConfigurators/HostConfigurator.cs
===================================================================
--- src/Topshelf/Configuration/HostConfigurators/HostConfigurator.cs (original)
+++ src/Topshelf/Configuration/HostConfigurators/HostConfigurator.cs (add SetArguments)
## -17,6 +17,12 ##
public interface HostConfigurator
{
/// <summary>
+ /// Specifies additional command line arguments that should be added when the service is registered
+ /// </summary>
+ /// <param name="name"> </param>
+ void SetArguments(string arguments);
+
+ /// <summary>
/// Specifies the name of the service as it should be displayed in the service control manager
/// </summary>
/// <param name="name"> </param>
Index: src/Topshelf/Configuration/Options/ArgumentsOption.cs
===================================================================
--- src/Topshelf/Configuration/Options/ArgumentsOption.cs (nonexistent)
+++ src/Topshelf/Configuration/Options/ArgumentsOption.cs (add SetArguments)
## -0,0 +1,31 ##
+// Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+// this file except in compliance with the License. You may obtain a copy of the
+// License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+namespace Topshelf.Options
+{
+ using HostConfigurators;
+
+ public class ArgumentsOption : Option
+ {
+ string _arguments;
+
+ public ArgumentsOption(string arguments)
+ {
+ _arguments = arguments;
+ }
+
+ public void ApplyTo(HostConfigurator configurator)
+ {
+ configurator.SetArguments(_arguments);
+ }
+ }
+}
\ No newline at end of file
Index: src/Topshelf/HelpText.txt
===================================================================
--- src/Topshelf/HelpText.txt (original)
+++ src/Topshelf/HelpText.txt (add SetArguments)
## -28,8 +28,10 ##
installing
-description The service description the service should use when
installing
- -displayname The display name the the service should use when
+ -displayname The display name the service should use when
installing
+ -arguments The command line arguments the service should
+ also get when installing
start Starts the service if it is not already running
## -57,3 +59,10 ##
Installs the service, appending the instance name to the service name
so that the service can be installed multiple times. You may need to
tweak the log4net.config to make this play nicely with the log files.
+
+ service install -arguments "-configFile \"C:\my folder\service.config\""
+ Installs the service, appending the command line argument to the
+ service so that the service will always retrieve this information
+ when started.
+ If double quotes are needed within the arguments they must be
+ escaped by a backslash \" (see example).
You have really easy options
static void Main(String[] args)
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new Service1(args) };
ServiceBase.Run(ServicesToRun);
}
then
public Service1(String[] args)
{
if (args.Length==0) // terminate with appropriate error
else
folderPath = arg[0]; // as an example
}
then in your service setup you can/must include a path.
Or, simply read it from a settings file that will be where the exe is - which is another and normal way of doing this.
I'm trying to call a web service method from my PowerShell script but it's failing. Here is the C# code:
public MyTable InsertRow(MyTable data)
{
var dataContext = new MyEntities();
dataContext.MyTables.AddObject(data);
dataContext.SaveChanges();
return data;
}
This is how I call it in PowerShell:
$uri = "http://localhost/MyWcfService/MyService.svc?wsdl"
$svc = New-WebServiceProxy -Uri $uri -UseDefaultCredential
$t = $svc.GetType().Namespace
$attributes = New-Object($t + ".MyTable")
$attributes.Name = "Project X"
$attributes.Comment = "This is a test"
$resp = $svc.InsertRow($attributes)
$resp
And this is the error that I get:
Cannot find an overload for "InsertRow" and the argument count: "1". At line:1 char:1
+ $resp = $svc.InsertRow($attributes)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
What am I doing wrong?
Update:
This is the built-in .NET type when I call $attributes.GetType():
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True MyTable Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1WcfService_MyService_s...
I gave up on trying to call my RESTful Web service in PowerShell. I used this tutorial to create entity data in a data service and then used this sample code to consume the service using C#. This I have not yet tried, but I should be able to use the C# code in PowerShell script (this being my project's requirement).
I am trying to call ghost script from my C# program, passing it some args to crop the footer of a PDF file, then overwrite the temp file with the new modified version.
I think I'm calling the gs.exe incorrectly. Does anyone see a reason that the string I'm passing to start(gs) doesn't work?
When trace the script, it triggers the catch when it gets to System.Diagnostics.Process.Start(gs);
This is the string that's being called in the process.start(gs) function
C:\gs\gs9.14\bin\gswin64c.exe -o C:\Users\myname\Desktop\assignment1\assignment1\data\temp\test.pdf -sDEVICE=pdfwrite -c "[/CropBox [24 72 559 794] /PAGES pdf mark" -f C:\Users\myname\Desktop\assignment1\assignment1\data\temp\test.pdf
This is the message that I get in my console.
System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start(String fileName)
at assignment1.Program.cropPDFFooter(String tempPDF) in C:\Users\tessierd\Desktop\assignment1\assignment1\Program.cs:line 78
Then this is the code for my method.
public static void cropPDFFooter(string tempPDF)
{
try
{
byte[] croppedPDF = File.ReadAllBytes(tempPDF);
string gsPath = #"C:\gs\gs9.14\bin\gswin64c.exe";
List<string> gsArgsList = new List<string>();
gsArgsList.Add(" -o " + tempPDF);
gsArgsList.Add(" -sDEVICE=pdfwrite");
gsArgsList.Add(" -c \"[/CropBox [24 72 559 794] /PAGES pdfmark\"");
gsArgsList.Add(" -f " + tempPDF);
var gsArgs = String.Join(null, gsArgsList);
string gs = gsPath + gsArgs; // not needed anymore (see solution)
// * wrong code here.
// System.Diagnostics.Process.Start(gs);
// * Correct code below.
System.Diagnostics.Process.Start(gsPath, gsArgs);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadLine();
}
}
System.Diagnostics.Process.Start(gs); takes 2 parms. a file, and then args.
I had to change the code to
System.Diagnostics.Process.Start(gsPath, gsArgs);
I would suggest you to use Ghostscript wrapper for .NET.
You can find one here: Ghostscript.NET on GitHub
Usage example can be found here: Ghostscript Processor C# Sample
There is also an example on how to add the watermark with a -c switch which postscript you can simply replace with your cropbox postscript: Ghostscript.NET - Passing Postscript commands (take a look at the bottom function)
Hi I have written new functionality in the existing webservice.
I am copying the proxy file when rebuilding and copying to the specific location
i am using powershell but its not working .i get the following error.
**The term 'wsdl.exe' is not recognized as the name of a cmdlet, function, script
file, or operable program. Check the spelling of the name, or if a path was in
cluded, verify that the path is correct and try again.
At C:\[path edited for security]\RebuildProxy.ps1:30 char:9
+ wsdl.exe <<<< /fields "/l:CS" "/n:$namespace" "/out:$outCSFile" "/urlkey:Tes
tEndpoint" "$wsdlUrl";
+ CategoryInfo : ObjectNotFound: (wsdl.exe:String) [], CommandNot
FoundException
+ FullyQualifiedErrorId : CommandNotFoundException**
After rebuild i get the message the file has been modified outside the source editor[ the generated proxy file already there in the location]
could you please help me on this
posted below the powershell code
param (
[string]$webServiceProjFile = $(throw "webServiceProjFile paramter is required." ),
[string]$serviceFile = $(throw "serviceFile parameter is required."),
[string]$outCSFile = $(throw "outCSFile paramter is required." )
)
if (! [IO.File]::Exists($webServiceProjFile))
{
throw "$webServiceProjFile note found.";
}
if (! [IO.File]::Exists($outCSFile))
{
throw "$outCSFile note found.";
}
# read the project file into an XML document.
$projectFileXml = [xml] (Get-Content $webServiceProjFile );
# access the configured IIS URL
$serviceWsdlUrl = [string]::Concat($projectFileXml.Project.ProjectExtensions.VisualStudio.FlavorProperties.WebProjectProperties.IISUrl.Trim(), '/', $serviceFile);
$namespace = "";
# Read the namespace for the proxy from the proxy C# file
Get-Content $outCSFile | ForEach-Object { if ($_ -match "^\s*namespace\s+([A-Za-z._]+)\s+{\s*$") { $namespace = $matches[1] }};
$wsdlUrl = [string]::Concat("$serviceWsdlUrl", '?wsdl');
# Regenerate the proxy using WSDL.exe
wsdl.exe /fields "/l:CS" "/n:$namespace" "/out:$outCSFile" "/urlkey:TestEndpoint" "$wsdlUrl";
# Update the generated C# file so the proxy class interits from WSE2 base class.
(Get-Content $outCSFile) |
ForEach-Object { $_ -replace "\s+\:\s+System\.Web\.Services\.Protocols\.SoapHttpClientProtocol", " : Microsoft.Web.Services2.WebServicesClientProtocol" } |
Set-Content $outCSFile ;
$projectDirectory = [IO.Path]::GetDirectoryName($outCSFile);
$appConfigFilePath = [IO.Path]::Combine($projectDirectory, "App.config");
(Get-Content $appConfigFilePath) |
ForEach-Object { $_ -replace '<add\s+key="TestEndpoint"\s+value="[^"]*"\s+/>', "<add key=""TestEndpoint"" value=""$serviceWsdlUrl"" />" } |
Set-Content $appConfigFilePath ;
WSDL.EXE is not in the path. On my computer it comes with the visual studio.
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\x64\wsdl.exe