I was wondering if it is possible to retreive from Windows a list of the applications installed INCLUDING their GUID and Upgrade GUID. I am having problems getting my upgrade to work for one of my programs, and need to check these values for the old version of the program. Thanks for the help!
You can use MSI api functions to enumerate all installed products and to query their properties. If you replace MsiGetProductInfo with MsiGetProductInfoEx you will be able to query additional information such as the installation context or user SID associated for an installation.
However, this does not allow you to enumerate the UpgradeCode. As far as I know MSI doesn't keep a record associating a ProductCode with an UpgradeCode; only the reverse mapping is available and you can enumerate the products related to an UpgradeCode using the MsiEnumRelatedProducts function.
Below you will find sample code which enumerates the installed or advertised products and their ProductCode using C#:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
class Program
{
[DllImport("msi.dll", CharSet = CharSet.Unicode)]
static extern Int32 MsiGetProductInfo(string product, string property,
[Out] StringBuilder valueBuf, ref Int32 len);
[DllImport("msi.dll", SetLastError = true)]
static extern int MsiEnumProducts(int iProductIndex,
StringBuilder lpProductBuf);
static void Main(string[] args)
{
StringBuilder sbProductCode = new StringBuilder(39);
int iIdx = 0;
while (MsiEnumProducts(iIdx++, sbProductCode) == 0)
{
Int32 productNameLen = 512;
StringBuilder sbProductName = new StringBuilder(productNameLen);
MsiGetProductInfo(sbProductCode.ToString(),
"ProductName", sbProductName, ref productNameLen);
Console.WriteLine("Product: {0}\t{1}", sbProductName, sbProductCode);
}
}
}
Update
If you still have the MSI installer of the previous version you can simply open the file using Orca and search for the UpgradeCode.
Related
Due to some bad practices from one of our internal users. We need to transfer all activities (mails, notes, etc) from one contact to another contact. I was trying to achieve this via UI and I could not find a way to do this.
Is this possible? I'm looking for any way to achieve this, wether is CRMTool, SSIS, UI or any other way. Only admins will do this so we do not need anything fancy as it will be done maybe 4 times a year to clean up some data.
Thanks a lot :)
Tried using UI but no success.
I can think of two ways to do these updates.
The first method is selecting a view on an activity where the owner is listed (i.e. All Phone Calls) and exporting to Excel. This downloads a XLSX with some hidden columns at the start where IDs for the records are kept. You then update the owner column with the new owner (take care of copying the exact fullname), and then importing the Excel spreadsheet again. You would need to repeat this export/import steps for each activity type (phone calls, email, etc.). So this might be impractical if you have a large volume of date, because of the need to repeat and because there are max numbers of records that you can export.
The other way to do this is using some .NET code. Of course, to do this you will need to use Visual Studio 2019.
If that's the case, this will do the trick:
using System;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Tooling.Connector;
namespace ChangeActivitiesOwner
{
class Program
{
static void Main(string[] args)
{
string connectionString = "AuthType=Office365;Url=<TODO:URL>;Username=<TODO:User>;Password=<TODO:Pass>;";
string oldUserFullname = ""; // TODO: place here fullname for the user you want to overwrite
string newUserFullname = ""; // TODO: place here fullname for the user you want to overwrite with
CrmServiceClient client = new CrmServiceClient(connectionString);
IOrganizationService service = client.OrganizationWebProxyClient != null ? client.OrganizationWebProxyClient : (IOrganizationService)client.OrganizationServiceProxy;
QueryByAttribute qbyaOldUser = new QueryByAttribute("systemuser");
qbyaOldUser.AddAttributeValue("fullname", oldUserFullname);
Guid olduserid = (Guid)service.RetrieveMultiple(qbyaOldUser)[0].Attributes["systemuserid"];
QueryByAttribute qbyaNewUser = new QueryByAttribute("systemuser");
qbyaNewUser.AddAttributeValue("fullname", newUserFullname);
Guid newuserid = (Guid)service.RetrieveMultiple(qbyaNewUser)[0].Attributes["systemuserid"];
foreach (string activity in new string[]{ "task", "phonecall", "email", "fax", "appointment", "letter", "campaignresponse", "campaignactivity" }) // TODO: Add other activities as needed!!!
{
QueryExpression query = new QueryExpression(activity)
{
ColumnSet = new ColumnSet("activityid", "ownerid")
};
query.Criteria.AddCondition(new ConditionExpression("ownerid", ConditionOperator.Equal, olduserid));
foreach (Entity e in service.RetrieveMultiple(query).Entities)
{
e.Attributes["ownerid"] = new EntityReference("systemuser", newuserid);
service.Update(e);
}
}
}
}
}
Please complete the lines marked with "TODO" with your info.
You will need to add the packages Microsoft.CrmSdk.CoreAssemblies, Microsoft.CrmSdk.Deployment, Microsoft.CrmSdk.Workflow, Microsoft.CrmSdk.XrmTooling.CoreAssembly, Microsoft.IdentityModel.Clients.ActiveDIrectory and Newtonsoft.Json to your solution, and use .NET Framework 4.6.2.
Hope this helps.
I downloaded the source code for FindPrivateKey.exe.
I use this exe to find the filename and folder for a private key. I have to run this locally on the machine. I am looking for a way to get this information remotely using web api.
FindPrivateKey.exe works by itself as a console app.
But in my webapi code, it does not work (CryptAcquireCertificatePrivateKey returns false)
Is there an obvious reason for this? The web api site has AllowAnonymousAccess enabled, is that why?
I'm having trouble including the code snippet. Summarizing:
StoreName is "My"
StoreLocation is "Local Machine"
//the call below returns false and this is where I am stuck
if (CryptAcquireCertificatePrivateKey(cert.Handle,
acquireFlags, IntPtr.Zero, ref hProvider, ref _keyNumber, ref freeProvider))
{
...
}
I was able to get this to work by first impersonating a user with rights to the private key information. For anyone interested, google the DllImport code below for how to do this.
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int LogonUser(
string lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
public extern static int DuplicateToken(
IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
So basically I was trying to access an Oracle database within unity and mono-develop. I copied the needed DLLs System.Data and System.Data.OracleClient
from under: C:\Program Files (x86)\Unity\Editor\Data\Mono\lib\mono\2.0
to the Project's Assets folder,
Here's my C# code:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.OracleClient;
public class OracleConn : MonoBehaviour
{
public string connectStr = "SomeConnectionString";
string TBName = "CZRK";
List<string> listOfID = new List<string>(); //ID
List<string> listOfName = new List<string>(); //NAME
private string content;
void Start()
{
OracleConnection conn = new OracleConnection(connectStr);
conn.Open(); //the line that causes error
}
}
then the error DllNotFoundException: oci pops out when executing conn.Open()
the full error log:
DllNotFoundException: oci
System.Data.OracleClient.Oci.OciCalls.OCIEnvCreate (System.IntPtr& envhpp, OciEnvironmentMode mode, IntPtr ctxp, IntPtr malocfp, IntPtr ralocfp, IntPtr mfreep, Int32 xtramem_sz, IntPtr usrmempp)
System.Data.OracleClient.Oci.OciEnvironmentHandle..ctor (OciEnvironmentMode mode)
System.Data.OracleClient.Oci.OciGlue.CreateConnection (OracleConnectionInfo conInfo)
System.Data.OracleClient.OracleConnectionPoolManager.CreateConnection (OracleConnectionInfo info)
System.Data.OracleClient.OracleConnectionPool.CreateConnection ()
System.Data.OracleClient.OracleConnectionPool.GetConnection ()
System.Data.OracleClient.OracleConnection.Open ()
(wrapper remoting-invoke-with-check) System.Data.OracleClient.OracleConnection:Open ()
OracleConn.Start () (at Assets/OracleConn.cs:25)
Besides, I also tried copy the DLL file oci.dll from oracleDB_11g into the assets folder, but problem remains, any ideas??
Got the same error on 5.5.0f3 also trying to hit 11g. My suspicion is the current set of drivers go up to 10g. Therefore I went 3rd party. I got https://www.devart.com/dotconnect/ working quickly. Note, I DO NOT work for them.
I have a windows service that can create an executable in the users windows session, via calling the "CreateProcessAsUser" function. This works fine as long as there is a windows session already there. In the case that there isn't one already I'd like to be able to create one programmatically. Is this is possible? Can't seem to find a function to do it.
This isn't quite the solution for the question I asked, but it was the solution that helped achieve what I was trying to achieve by asking this question, if you see what I mean.
Rather than have having a windows services that creates a server session you can configure windows to automatically logon at boot time. This still means someone could accenditally log off, but cures the main reason for sessions disappearing: the server being rebooted. Use the following steps to activate auto-logon:
Press the Windows key + R on your keyboard to launch the “Run” dialog box.
Type regedit and hit enter to open the Registry Editor
Then browse to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Winlogon\
Set AutoAdminLogon = 1 (create it if doesn't exist its a string variable)
Set DefaultUserName = your username (create it if doesn't exist its a string variable)
Set DefaultPassword = your password (create it if doesn't exist its a string variable)
Instructions were taken from this post:
http://channel9.msdn.com/Blogs/coolstuff/Tip-Auto-Login-Your-Windows-7-User-Account
You cannot create a new session from a service. Sessions are managed by the OS. New ones get created when users logon interactively.
#Robert, I know this is an old question and that you've already found something that works for you but in my case I was looking for something similar to your original question and I did finally figure it out so I thought I'd share. My solution uses only .NET and a COM reference not the Win32 API mentioned in your title, but I'm guessing that wasn't really a requirement for you.
I've written a simple utility to using the Remote Desktop ActiveX control (COM Reference). If you paste this code into a Class Library you can then call it by simply passing in the server, username, domain, and password and everything is done for you without any other interaction required. Once the method is complete you can then call your "CreateProcessAsUser" Code. I've written this utility in a way so that you could call it every time but initiating an RDP session takes several seconds so for performance sake I'd suggest you write another method to enumerate the sessions and see if your user is logged in and only call this utility when you determine that your user isn't logged in (That's what I did in my actual project). If you feel you need help with that post in the comments and I'll share how I did that but It's not really part of this question so for now I'm leaving it out.
Here's a link back to my question that has a few more requirements/details than this question.
Create Windows Session programmatically from Console or Windows Service
And here's my RDP utility. After you put this code in a class library you can then call it from a console app, winForms app, or from a windows service running on the same machine or from a remote machine.
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using AxMSTSCLib;
namespace Utility.RemoteDesktop
{
public class Client
{
private int LogonErrorCode { get; set; }
public void CreateRdpConnection(string server, string user, string domain, string password)
{
void ProcessTaskThread()
{
var form = new Form();
form.Load += (sender, args) =>
{
var rdpConnection = new AxMSTSCLib.AxMsRdpClient9NotSafeForScripting();
form.Controls.Add(rdpConnection);
rdpConnection.Server = server;
rdpConnection.Domain = domain;
rdpConnection.UserName = user;
rdpConnection.AdvancedSettings9.ClearTextPassword = password;
rdpConnection.AdvancedSettings9.EnableCredSspSupport = true;
if (true)
{
rdpConnection.OnDisconnected += RdpConnectionOnOnDisconnected;
rdpConnection.OnLoginComplete += RdpConnectionOnOnLoginComplete;
rdpConnection.OnLogonError += RdpConnectionOnOnLogonError;
}
rdpConnection.Connect();
rdpConnection.Enabled = false;
rdpConnection.Dock = DockStyle.Fill;
Application.Run(form);
};
form.Show();
}
var rdpClientThread = new Thread(ProcessTaskThread) { IsBackground = true };
rdpClientThread.SetApartmentState(ApartmentState.STA);
rdpClientThread.Start();
while (rdpClientThread.IsAlive)
{
Task.Delay(500).GetAwaiter().GetResult();
}
}
private void RdpConnectionOnOnLogonError(object sender, IMsTscAxEvents_OnLogonErrorEvent e)
{
LogonErrorCode = e.lError;
}
private void RdpConnectionOnOnLoginComplete(object sender, EventArgs e)
{
if (LogonErrorCode == -2)
{
Debug.WriteLine($" ## New Session Detected ##");
Task.Delay(10000).GetAwaiter().GetResult();
}
var rdpSession = (AxMsRdpClient9NotSafeForScripting)sender;
rdpSession.Disconnect();
}
private void RdpConnectionOnOnDisconnected(object sender, IMsTscAxEvents_OnDisconnectedEvent e)
{
Environment.Exit(0);
}
}
}
What about the LogonUser function?
http://winapi.freetechsecrets.com/win32/WIN32LogonUser.htm
I'm new to .NET. I want to make a console application that converts a .pptx file into a .wmv.I've managed to do this using powerpoint interop.But i have some problems.First If i build the application and tranfer it to another computer i get an exception Error HRESULT E_FAIL has been returned for COM object(i have powerpoint in both PCs).If i run it on the one that i wrote it i everything works alright.But not for the first time.Meaning that when i start my pc and run it i'll get the same exception and the second time i'll try to run it will run properly.What could be the problem?iguess something with interop and powerpoint but i can't figure it out.
Ok here is the code:
using Microsoft.Office.Core;
using Microsoft.Office.Interop.PowerPoint;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using System.Runtime.InteropServices;
using System.IO;
using System;
namespace Microsoft.Office.Interop.PowerPoint
{
class Program
{
static void Main(string[] args)
{
string fileName = args[0];
string exportName = args[1];
string exportPath = args[2];
Microsoft.Office.Interop.PowerPoint.Application ppApp = new Microsoft.Office.Interop.PowerPoint.Application();
ppApp.Visible = MsoTriState.msoTrue;
ppApp.WindowState = PpWindowState.ppWindowMinimized;
Microsoft.Office.Interop.PowerPoint.Presentations oPresSet = ppApp.Presentations;
Microsoft.Office.Interop.PowerPoint._Presentation oPres = oPresSet.Open(fileName,
MsoTriState.msoFalse, MsoTriState.msoFalse,
MsoTriState.msoFalse);
try
{
oPres.CreateVideo(exportName);
oPres.SaveCopyAs(String.Format(exportPath, exportName),
PowerPoint.PpSaveAsFileType.ppSaveAsWMV,
MsoTriState.msoCTrue);
}
finally
{
ppApp.Quit();
}
}
}
}
_Presentation.CreateVideo doesn't create a video out of a powerpoint. It creates a video inside of a powerpoint. That's what the documentation says, anyway.
Try _Presentation.SaveAs and then use PpSaveAsFileType.ppSaveAsWMV for the file type.